6
if ( typeof define === 'function' && define.amd ) {
8
define( ['jquery', 'datatables.net'], function ( $ ) {
9
return factory( $, window, document );
12
else if ( typeof exports === 'object' ) {
14
module.exports = function (root, $) {
19
if ( ! $ || ! $.fn.dataTable ) {
20
$ = require('datatables.net')(root, $).$;
23
return factory( $, root, root.document );
28
factory( jQuery, window, document );
30
}(function( $, window, document, undefined ) {
32
var DataTable = $.fn.dataTable;
40
var _buttonCounter = 0;
42
var _dtButtons = DataTable.ext.buttons;
45
function _fadeIn(el, duration, fn) {
49
.fadeIn( duration, fn );
53
el.css('display', 'block');
61
function _fadeOut(el, duration, fn) {
65
.fadeOut( duration, fn );
68
el.css('display', 'none');
81
var Buttons = function( dt, config )
86
if ( !(this instanceof Buttons) ) {
87
return function (settings) {
88
return new Buttons( settings, dt ).container();
93
if ( typeof( config ) === 'undefined' ) {
98
if ( config === true ) {
103
if ( Array.isArray( config ) ) {
104
config = { buttons: config };
107
this.c = $.extend( true, {}, Buttons.defaults, config );
110
if ( config.buttons ) {
111
this.c.buttons = config.buttons;
115
dt: new DataTable.Api( dt ),
118
namespace: 'dtb'+(_instCounter++)
122
container: $('<'+this.c.dom.container.tag+'/>')
123
.addClass( this.c.dom.container.className )
130
$.extend( Buttons.prototype, {
140
* Set the action of a button
141
* @param {node} node Button element
142
* @param {function} action Function to set
143
* @return {Buttons} Self for chaining
145
action: function ( node, action )
147
var button = this._nodeToButton( node );
149
if ( action === undefined ) {
150
return button.conf.action;
153
button.conf.action = action;
165
active: function ( node, flag ) {
166
var button = this._nodeToButton( node );
167
var klass = this.c.dom.button.active;
168
var jqNode = $(button.node);
170
if ( flag === undefined ) {
171
return jqNode.hasClass( klass );
174
jqNode.toggleClass( klass, flag === undefined ? true : flag );
187
add: function ( config, idx, draw )
189
var buttons = this.s.buttons;
191
if ( typeof idx === 'string' ) {
192
var split = idx.split('-');
195
for ( var i=0, ien=split.length-1 ; i<ien ; i++ ) {
196
base = base.buttons[ split[i]*1 ];
199
buttons = base.buttons;
200
idx = split[ split.length-1 ]*1;
206
config !== undefined ? config.split : undefined,
207
(config === undefined || config.split === undefined || config.split.length === 0) && base !== undefined,
212
if (draw === undefined || draw === true) {
222
collectionRebuild: function ( node, newButtons )
224
var button = this._nodeToButton( node );
226
if(newButtons !== undefined) {
229
for (i=button.buttons.length-1; i>=0; i--) {
230
this.remove(button.buttons[i].node);
233
for (i=0; i<newButtons.length; i++) {
234
var newBtn = newButtons[i];
239
newBtn !== undefined && newBtn.config !== undefined && newBtn.config.split !== undefined,
241
newBtn.parentConf !== undefined && newBtn.parentConf.split !== undefined,
248
this._draw(button.collection, button.buttons);
255
container: function ()
257
return this.dom.container;
265
disable: function ( node ) {
266
var button = this._nodeToButton( node );
269
.addClass( this.c.dom.button.disabled )
270
.attr('disabled', true);
283
$('body').off( 'keyup.'+this.s.namespace );
287
var buttons = this.s.buttons.slice();
290
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
291
this.remove( buttons[i].node );
295
this.dom.container.remove();
298
var buttonInsts = this.s.dt.settings()[0];
300
for ( i=0, ien=buttonInsts.length ; i<ien ; i++ ) {
301
if ( buttonInsts.inst === this ) {
302
buttonInsts.splice( i, 1 );
316
enable: function ( node, flag )
318
if ( flag === false ) {
319
return this.disable( node );
322
var button = this._nodeToButton( node );
324
.removeClass( this.c.dom.button.disabled )
325
.removeAttr('disabled');
337
index: function ( node, nested, buttons )
341
buttons = this.s.buttons;
344
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
345
var inner = buttons[i].buttons;
347
if (buttons[i].node === node) {
351
if ( inner && inner.length ) {
352
var match = this.index(node, i + '-', inner);
354
if (match !== null) {
378
node: function ( node )
381
return this.dom.container;
384
var button = this._nodeToButton( node );
385
return $(button.node);
394
processing: function ( node, flag )
397
var button = this._nodeToButton( node );
399
if ( flag === undefined ) {
400
return $(button.node).hasClass( 'processing' );
403
$(button.node).toggleClass( 'processing', flag );
405
$(dt.table().node()).triggerHandler( 'buttons-processing.dt', [
406
flag, dt.button( node ), dt, $(node), button.conf
417
remove: function ( node )
419
var button = this._nodeToButton( node );
420
var host = this._nodeToHost( node );
424
if ( button.buttons.length ) {
425
for ( var i=button.buttons.length-1 ; i>=0 ; i-- ) {
426
this.remove( button.buttons[i].node );
430
button.conf.destroying = true;
433
if ( button.conf.destroy ) {
434
button.conf.destroy.call( dt.button(node), dt, $(node), button.conf );
437
this._removeKey( button.conf );
439
$(button.node).remove();
441
var idx = $.inArray( button, host );
442
host.splice( idx, 1 );
452
* Set the text for a button
453
* @param {int|string|function} node Button index
454
* @param {string} label Text
455
* @return {Buttons} Self for chaining
457
text: function ( node, label )
459
var button = this._nodeToButton( node );
460
var buttonLiner = this.c.dom.collection.buttonLiner;
461
var linerTag = button.inCollection && buttonLiner && buttonLiner.tag ?
463
this.c.dom.buttonLiner.tag;
465
var jqNode = $(button.node);
466
var text = function ( opt ) {
467
return typeof opt === 'function' ?
468
opt( dt, jqNode, button.conf ) :
472
if ( label === undefined ) {
473
return text( button.conf.text );
476
button.conf.text = label;
480
.children( linerTag )
482
.filter(':not(.dt-down-arrow)')
483
.html( text(label) );
486
jqNode.html( text(label) );
501
_constructor: function ()
505
var dtSettings = dt.settings()[0];
506
var buttons = this.c.buttons;
508
if ( ! dtSettings._buttons ) {
509
dtSettings._buttons = [];
512
dtSettings._buttons.push( {
517
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
518
this.add( buttons[i] );
521
dt.on( 'destroy', function ( e, settings ) {
522
if ( settings === dtSettings ) {
528
$('body').on( 'keyup.'+this.s.namespace, function ( e ) {
529
if ( ! document.activeElement || document.activeElement === document.body ) {
532
var character = String.fromCharCode(e.keyCode).toLowerCase();
534
if ( that.s.listenKeys.toLowerCase().indexOf( character ) !== -1 ) {
535
that._keypress( character, e );
551
_addKey: function ( conf )
554
this.s.listenKeys += $.isPlainObject( conf.key ) ?
566
_draw: function ( container, buttons )
569
container = this.dom.container;
570
buttons = this.s.buttons;
573
container.children().detach();
575
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
576
container.append( buttons[i].inserter );
577
container.append( ' ' );
579
if ( buttons[i].buttons && buttons[i].buttons.length ) {
580
this._draw( buttons[i].collection, buttons[i].buttons );
592
_expandButton: function ( attachTo, button, split, inCollection, inSplit, attachPoint, parentConf )
595
var buttonCounter = 0;
597
var buttons = ! Array.isArray( button ) ?
601
if(button === undefined ) {
602
buttons = !Array.isArray(split) ?
607
if (button !== undefined && button.split !== undefined) {
611
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
612
var conf = this._resolveExtends( buttons[i] );
618
if( conf.config !== undefined && conf.config.split) {
627
if ( Array.isArray( conf ) ) {
628
this._expandButton( attachTo, conf, built !== undefined && built.conf !== undefined ? built.conf.split : undefined, inCollection, parentConf !== undefined && parentConf.split !== undefined, attachPoint, parentConf );
632
var built = this._buildButton( conf, inCollection, conf.split !== undefined || (conf.config !== undefined && conf.config.split !== undefined), inSplit );
637
if ( attachPoint !== undefined && attachPoint !== null ) {
638
attachTo.splice( attachPoint, 0, built );
642
attachTo.push( built );
646
if ( built.conf.buttons || built.conf.split ) {
647
built.collection = $('<'+(isSplit ? this.c.dom.splitCollection.tag : this.c.dom.collection.tag)+'/>');
649
built.conf._collection = built.collection;
651
if(built.conf.split) {
652
for(var j = 0; j < built.conf.split.length; j++) {
653
if(typeof built.conf.split[j] === "object") {
654
built.conf.split[j].parent = parentConf;
655
if(built.conf.split[j].collectionLayout === undefined) {
656
built.conf.split[j].collectionLayout = built.conf.collectionLayout;
658
if(built.conf.split[j].dropup === undefined) {
659
built.conf.split[j].dropup = built.conf.dropup;
661
if(built.conf.split[j].fade === undefined) {
662
built.conf.split[j].fade = built.conf.fade;
668
$(built.node).append($('<span class="dt-down-arrow">'+this.c.dom.splitDropdown.text+'</span>'))
671
this._expandButton( built.buttons, built.conf.buttons, built.conf.split, !isSplit, isSplit, attachPoint, built.conf );
673
built.conf.parent = parentConf;
678
conf.init.call( dt.button( built.node ), dt, $(built.node), conf );
692
_buildButton: function ( config, inCollection, isSplit, inSplit )
694
var buttonDom = this.c.dom.button;
695
var linerDom = this.c.dom.buttonLiner;
696
var collectionDom = this.c.dom.collection;
697
var splitDom = this.c.dom.split;
698
var splitCollectionDom = this.c.dom.splitCollection;
699
var splitDropdownButton = this.c.dom.splitDropdownButton;
701
var text = function ( opt ) {
702
return typeof opt === 'function' ?
703
opt( dt, button, config ) :
709
var spacer = $('<span></span>')
710
.addClass('dt-button-spacer ' + config.style + ' ' + buttonDom.spacerClass)
711
.html(text(config.text));
718
inCollection: inCollection,
725
if ( !isSplit && inSplit && splitCollectionDom ) {
726
buttonDom = splitDropdownButton;
728
else if ( !isSplit && inCollection && collectionDom.button ) {
729
buttonDom = collectionDom.button;
732
if ( !isSplit && inSplit && splitCollectionDom.buttonLiner ) {
733
linerDom = splitCollectionDom.buttonLiner
735
else if ( !isSplit && inCollection && collectionDom.buttonLiner ) {
736
linerDom = collectionDom.buttonLiner;
741
if ( config.available && ! config.available( dt, config ) && !config.hasOwnProperty('html') ) {
746
if(!config.hasOwnProperty('html')) {
747
var action = function ( e, dt, button, config ) {
748
config.action.call( dt.button( button ), e, dt, button, config );
750
$(dt.table().node()).triggerHandler( 'buttons-action.dt', [
751
dt.button( button ), dt, button, config
755
var tag = config.tag || buttonDom.tag;
756
var clickBlurs = config.clickBlurs === undefined
760
button = $('<'+tag+'/>')
761
.addClass( buttonDom.className )
762
.addClass( inSplit ? this.c.dom.splitDropdownButton.className : '')
763
.attr( 'tabindex', this.s.dt.settings()[0].iTabIndex )
764
.attr( 'aria-controls', this.s.dt.table().node().id )
765
.on( 'click.dtb', function (e) {
768
if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
769
action( e, dt, button, config );
772
button.trigger('blur');
775
.on( 'keypress.dtb', function (e) {
776
if ( e.keyCode === 13 ) {
779
if ( ! button.hasClass( buttonDom.disabled ) && config.action ) {
780
action( e, dt, button, config );
786
if ( tag.toLowerCase() === 'a' ) {
787
button.attr( 'href', '#' );
791
if ( tag.toLowerCase() === 'button' ) {
792
button.attr( 'type', 'button' );
795
if ( linerDom.tag ) {
796
var liner = $('<'+linerDom.tag+'/>')
797
.html( text( config.text ) )
798
.addClass( linerDom.className );
800
if ( linerDom.tag.toLowerCase() === 'a' ) {
801
liner.attr( 'href', '#' );
804
button.append( liner );
807
button.html( text( config.text ) );
810
if ( config.enabled === false ) {
811
button.addClass( buttonDom.disabled );
814
if ( config.className ) {
815
button.addClass( config.className );
818
if ( config.titleAttr ) {
819
button.attr( 'title', text( config.titleAttr ) );
823
button.attr( config.attr );
826
if ( ! config.namespace ) {
827
config.namespace = '.dt-button-'+(_buttonCounter++);
830
if ( config.config !== undefined && config.config.split ) {
831
config.split = config.config.split;
835
button = $(config.html)
838
var buttonContainer = this.c.dom.buttonContainer;
840
if ( buttonContainer && buttonContainer.tag ) {
841
inserter = $('<'+buttonContainer.tag+'/>')
842
.addClass( buttonContainer.className )
849
this._addKey( config );
854
if( this.c.buttonCreated ) {
855
inserter = this.c.buttonCreated( config, inserter );
860
splitDiv = $('<div/>').addClass(this.c.dom.splitWrapper.className)
861
splitDiv.append(button);
862
var dropButtonConfig = $.extend(config, {
863
text: this.c.dom.splitDropdown.text,
864
className: this.c.dom.splitDropdown.className,
867
'aria-haspopup': true,
868
'aria-expanded': false
870
align: this.c.dom.splitDropdown.align,
871
splitAlignClass: this.c.dom.splitDropdown.splitAlignClass
875
this._addKey(dropButtonConfig);
877
var splitAction = function ( e, dt, button, config ) {
878
_dtButtons.split.action.call( dt.button($('div.dt-btn-split-wrapper')[0] ), e, dt, button, config );
880
$(dt.table().node()).triggerHandler( 'buttons-action.dt', [
881
dt.button( button ), dt, button, config
883
button.attr('aria-expanded', true)
886
var dropButton = $('<button class="' + this.c.dom.splitDropdown.className + ' dt-button"><span class="dt-btn-split-drop-arrow">'+this.c.dom.splitDropdown.text+'</span></button>')
887
.on( 'click.dtb', function (e) {
891
if ( ! dropButton.hasClass( buttonDom.disabled )) {
892
splitAction( e, dt, dropButton, dropButtonConfig );
895
dropButton.trigger('blur');
898
.on( 'keypress.dtb', function (e) {
899
if ( e.keyCode === 13 ) {
902
if ( ! dropButton.hasClass( buttonDom.disabled ) ) {
903
splitAction( e, dt, dropButton, dropButtonConfig );
908
if(config.split.length === 0) {
909
dropButton.addClass('dtb-hide-drop');
912
splitDiv.append(dropButton).attr(dropButtonConfig.attr);
917
node: isSplit ? splitDiv.get(0) : button.get(0),
918
inserter: isSplit ? splitDiv : inserter,
920
inCollection: inCollection,
934
_nodeToButton: function ( node, buttons )
937
buttons = this.s.buttons;
940
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
941
if ( buttons[i].node === node ) {
945
if ( buttons[i].buttons.length ) {
946
var ret = this._nodeToButton( node, buttons[i].buttons );
962
_nodeToHost: function ( node, buttons )
965
buttons = this.s.buttons;
968
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
969
if ( buttons[i].node === node ) {
973
if ( buttons[i].buttons.length ) {
974
var ret = this._nodeToHost( node, buttons[i].buttons );
990
_keypress: function ( character, e )
993
if ( e._buttonsHandled ) {
997
var run = function ( conf, node ) {
1002
if ( conf.key === character ) {
1003
e._buttonsHandled = true;
1006
else if ( $.isPlainObject( conf.key ) ) {
1007
if ( conf.key.key !== character ) {
1011
if ( conf.key.shiftKey && ! e.shiftKey ) {
1015
if ( conf.key.altKey && ! e.altKey ) {
1019
if ( conf.key.ctrlKey && ! e.ctrlKey ) {
1023
if ( conf.key.metaKey && ! e.metaKey ) {
1028
e._buttonsHandled = true;
1033
var recurse = function ( a ) {
1034
for ( var i=0, ien=a.length ; i<ien ; i++ ) {
1035
run( a[i].conf, a[i].node );
1037
if ( a[i].buttons.length ) {
1038
recurse( a[i].buttons );
1043
recurse( this.s.buttons );
1052
_removeKey: function ( conf )
1055
var character = $.isPlainObject( conf.key ) ?
1061
var a = this.s.listenKeys.split('');
1062
var idx = $.inArray( character, a );
1064
this.s.listenKeys = a.join('');
1074
_resolveExtends: function ( conf )
1079
var toConfObject = function ( base ) {
1085
while ( ! $.isPlainObject(base) && ! Array.isArray(base) ) {
1086
if ( base === undefined ) {
1090
if ( typeof base === 'function' ) {
1091
base = base.call( that, dt, conf );
1097
else if ( typeof base === 'string' ) {
1098
if ( ! _dtButtons[ base ] ) {
1102
base = _dtButtons[ base ];
1108
throw 'Buttons: Too many iterations';
1112
return Array.isArray( base ) ?
1114
$.extend( {}, base );
1117
conf = toConfObject( conf );
1119
while ( conf && conf.extend ) {
1122
if ( ! _dtButtons[ conf.extend ] ) {
1123
throw 'Cannot extend unknown button type: '+conf.extend;
1126
var objArray = toConfObject( _dtButtons[ conf.extend ] );
1127
if ( Array.isArray( objArray ) ) {
1130
else if ( ! objArray ) {
1138
var originalClassName = objArray.className;
1140
if (conf.config !== undefined && objArray.config !== undefined) {
1141
conf.config = $.extend({}, objArray.config, conf.config)
1144
conf = $.extend( {}, objArray, conf );
1149
if ( originalClassName && conf.className !== originalClassName ) {
1150
conf.className = originalClassName+' '+conf.className;
1155
var postfixButtons = conf.postfixButtons;
1156
if ( postfixButtons ) {
1157
if ( ! conf.buttons ) {
1161
for ( i=0, ien=postfixButtons.length ; i<ien ; i++ ) {
1162
conf.buttons.push( postfixButtons[i] );
1165
conf.postfixButtons = null;
1168
var prefixButtons = conf.prefixButtons;
1169
if ( prefixButtons ) {
1170
if ( ! conf.buttons ) {
1174
for ( i=0, ien=prefixButtons.length ; i<ien ; i++ ) {
1175
conf.buttons.splice( i, 0, prefixButtons[i] );
1178
conf.prefixButtons = null;
1184
conf.extend = objArray.extend;
1196
_popover: function ( content, hostButton, inOpts, e ) {
1197
var dt = hostButton;
1198
var buttonsSettings = this.c;
1200
var options = $.extend( {
1201
align: 'button-left',
1204
backgroundClassName: 'dt-button-background',
1206
contentClassName: buttonsSettings.dom.collection.className,
1207
collectionLayout: '',
1208
collectionTitle: '',
1212
rightAlignClassName: 'dt-button-right',
1213
tag: buttonsSettings.dom.collection.tag
1216
var hostNode = hostButton.node();
1218
var close = function () {
1222
$('.dt-button-collection'),
1229
$(dt.buttons( '[aria-haspopup="true"][aria-expanded="true"]' ).nodes())
1230
.attr('aria-expanded', 'false');
1232
$('div.dt-button-background').off( 'click.dtb-collection' );
1233
Buttons.background( false, options.backgroundClassName, options.fade, hostNode );
1235
$(window).off('resize.resize.dtb-collection');
1236
$('body').off( '.dtb-collection' );
1237
dt.off( 'buttons-action.b-internal' );
1238
dt.off( 'destroy' );
1241
if (content === false) {
1246
var existingExpanded = $(dt.buttons( '[aria-haspopup="true"][aria-expanded="true"]' ).nodes());
1247
if ( existingExpanded.length ) {
1249
if (hostNode.closest('div.dt-button-collection').length) {
1250
hostNode = existingExpanded.eq(0);
1257
var cnt = $('.dt-button', content).length;
1263
else if (cnt === 2) {
1266
else if (cnt === 1) {
1270
var display = $('<div/>')
1271
.addClass('dt-button-collection')
1272
.addClass(options.collectionLayout)
1273
.addClass(options.splitAlignClass)
1275
.css('display', 'none');
1277
content = $(content)
1278
.addClass(options.contentClassName)
1279
.attr('role', 'menu')
1282
hostNode.attr( 'aria-expanded', 'true' );
1284
if ( hostNode.parents('body')[0] !== document.body ) {
1285
hostNode = document.body.lastChild;
1288
if ( options.popoverTitle ) {
1289
display.prepend('<div class="dt-button-collection-title">'+options.popoverTitle+'</div>');
1291
else if ( options.collectionTitle ) {
1292
display.prepend('<div class="dt-button-collection-title">'+options.collectionTitle+'</div>');
1295
if (options.closeButton) {
1296
display.prepend('<div class="dtb-popover-close">x</div>').addClass('dtb-collection-closeable')
1299
_fadeIn( display.insertAfter( hostNode ), options.fade );
1301
var tableContainer = $( hostButton.table().container() );
1302
var position = display.css( 'position' );
1304
if ( options.span === 'container' || options.align === 'dt-container' ) {
1305
hostNode = hostNode.parent();
1306
display.css('width', tableContainer.width());
1311
if (position === 'absolute') {
1313
var offsetParent = $(hostNode[0].offsetParent);
1314
var buttonPosition = hostNode.position();
1315
var buttonOffset = hostNode.offset();
1316
var tableSizes = offsetParent.offset();
1317
var containerPosition = offsetParent.position();
1318
var computed = window.getComputedStyle(offsetParent[0]);
1320
tableSizes.height = offsetParent.outerHeight();
1321
tableSizes.width = offsetParent.width() + parseFloat(computed.paddingLeft);
1322
tableSizes.right = tableSizes.left + tableSizes.width;
1323
tableSizes.bottom = tableSizes.top + tableSizes.height;
1326
var top = buttonPosition.top + hostNode.outerHeight();
1327
var left = buttonPosition.left;
1335
computed = window.getComputedStyle(display[0]);
1336
var popoverSizes = display.offset();
1338
popoverSizes.height = display.outerHeight();
1339
popoverSizes.width = display.outerWidth();
1340
popoverSizes.right = popoverSizes.left + popoverSizes.width;
1341
popoverSizes.bottom = popoverSizes.top + popoverSizes.height;
1342
popoverSizes.marginTop = parseFloat(computed.marginTop);
1343
popoverSizes.marginBottom = parseFloat(computed.marginBottom);
1346
if (options.dropup) {
1347
top = buttonPosition.top - popoverSizes.height - popoverSizes.marginTop - popoverSizes.marginBottom;
1350
if (options.align === 'button-right' || display.hasClass( options.rightAlignClassName )) {
1351
left = buttonPosition.left - popoverSizes.width + hostNode.outerWidth();
1355
if (options.align === 'dt-container' || options.align === 'container') {
1356
if (left < buttonPosition.left) {
1357
left = -buttonPosition.left;
1360
if (left + popoverSizes.width > tableSizes.width) {
1361
left = tableSizes.width - popoverSizes.width;
1366
if (containerPosition.left + left + popoverSizes.width > $(window).width()) {
1368
left = $(window).width() - popoverSizes.width - containerPosition.left;
1371
if (buttonOffset.left + left < 0) {
1373
left = -buttonOffset.left;
1376
if (containerPosition.top + top + popoverSizes.height > $(window).height() + $(window).scrollTop()) {
1378
top = buttonPosition.top - popoverSizes.height - popoverSizes.marginTop - popoverSizes.marginBottom;
1381
if (containerPosition.top + top < $(window).scrollTop()) {
1383
top = buttonPosition.top + hostNode.outerHeight();
1394
var position = function () {
1395
var half = $(window).height() / 2;
1397
var top = display.height() / 2;
1402
display.css( 'marginTop', top*-1 );
1407
$(window).on('resize.dtb-collection', function () {
1412
if ( options.background ) {
1415
options.backgroundClassName,
1417
options.backgroundHost || hostNode
1425
$('div.dt-button-background').on( 'click.dtb-collection', function () {} );
1427
if ( options.autoClose ) {
1428
setTimeout( function () {
1429
dt.on( 'buttons-action.b-internal', function (e, btn, dt, node) {
1430
if ( node[0] === hostNode[0] ) {
1438
$(display).trigger('buttons-popover.dt');
1441
dt.on('destroy', close);
1443
setTimeout(function() {
1446
.on( 'click.dtb-collection', function (e) {
1452
var back = $.fn.addBack ? 'addBack' : 'andSelf';
1453
var parent = $(e.target).parent()[0];
1455
if (( ! $(e.target).parents()[back]().filter( content ).length && !$(parent).hasClass('dt-buttons')) || $(e.target).hasClass('dt-button-background')) {
1459
.on( 'keyup.dtb-collection', function (e) {
1460
if ( e.keyCode === 27 ) {
1481
Buttons.background = function ( show, className, fade, insertPoint ) {
1482
if ( fade === undefined ) {
1485
if ( ! insertPoint ) {
1486
insertPoint = document.body;
1492
.addClass( className )
1493
.css( 'display', 'none' )
1494
.insertAfter( insertPoint ),
1500
$('div.'+className),
1504
.removeClass( className )
1522
Buttons.instanceSelector = function ( group, buttons )
1524
if ( group === undefined || group === null ) {
1525
return $.map( buttons, function ( v ) {
1531
var names = $.map( buttons, function ( v ) {
1536
var process = function ( input ) {
1537
if ( Array.isArray( input ) ) {
1538
for ( var i=0, ien=input.length ; i<ien ; i++ ) {
1539
process( input[i] );
1544
if ( typeof input === 'string' ) {
1545
if ( input.indexOf( ',' ) !== -1 ) {
1547
process( input.split(',') );
1551
var idx = $.inArray( input.trim(), names );
1554
ret.push( buttons[ idx ].inst );
1558
else if ( typeof input === 'number' ) {
1560
ret.push( buttons[ input ].inst );
1562
else if ( typeof input === 'object' ) {
1583
Buttons.buttonSelector = function ( insts, selector )
1586
var nodeBuilder = function ( a, buttons, baseIdx ) {
1590
for ( var i=0, ien=buttons.length ; i<ien ; i++ ) {
1591
button = buttons[i];
1594
idx = baseIdx !== undefined ?
1600
name: button.conf.name,
1604
if ( button.buttons ) {
1605
nodeBuilder( a, button.buttons, idx+'-' );
1611
var run = function ( selector, inst ) {
1614
nodeBuilder( buttons, inst.s.buttons );
1616
var nodes = $.map( buttons, function (v) {
1620
if ( Array.isArray( selector ) || selector instanceof $ ) {
1621
for ( i=0, ien=selector.length ; i<ien ; i++ ) {
1622
run( selector[i], inst );
1627
if ( selector === null || selector === undefined || selector === '*' ) {
1629
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
1632
node: buttons[i].node
1636
else if ( typeof selector === 'number' ) {
1638
if (inst.s.buttons[ selector ]) {
1641
node: inst.s.buttons[ selector ].node
1645
else if ( typeof selector === 'string' ) {
1646
if ( selector.indexOf( ',' ) !== -1 ) {
1648
var a = selector.split(',');
1650
for ( i=0, ien=a.length ; i<ien ; i++ ) {
1651
run( a[i].trim(), inst );
1654
else if ( selector.match( /^\d+(\-\d+)*$/ ) ) {
1656
var indexes = $.map( buttons, function (v) {
1662
node: buttons[ $.inArray( selector, indexes ) ].node
1665
else if ( selector.indexOf( ':name' ) !== -1 ) {
1667
var name = selector.replace( ':name', '' );
1669
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
1670
if ( buttons[i].name === name ) {
1673
node: buttons[i].node
1680
$( nodes ).filter( selector ).each( function () {
1688
else if ( typeof selector === 'object' && selector.nodeName ) {
1690
var idx = $.inArray( selector, nodes );
1702
for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
1703
var inst = insts[i];
1705
run( selector, inst );
1715
Buttons.stripData = function ( str, config ) {
1716
if ( typeof str !== 'string' ) {
1721
str = str.replace( /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '' );
1724
str = str.replace( /<!\-\-.*?\-\->/g, '' );
1726
if ( ! config || config.stripHtml ) {
1727
str = str.replace( /<[^>]*>/g, '' );
1730
if ( ! config || config.trim ) {
1731
str = str.replace( /^\s+|\s+$/g, '' );
1734
if ( ! config || config.stripNewlines ) {
1735
str = str.replace( /\n/g, ' ' );
1738
if ( ! config || config.decodeEntities ) {
1739
_exportTextarea.innerHTML = str;
1740
str = _exportTextarea.value;
1754
buttons: [ 'copy', 'excel', 'csv', 'pdf', 'print' ],
1760
className: 'dt-buttons'
1768
className: 'dt-button',
1770
disabled: 'disabled',
1779
className: 'dt-button-split',
1783
className: 'dt-btn-split-wrapper',
1788
className: 'dt-btn-split-drop',
1789
align: 'split-right',
1790
splitAlignClass: 'dt-button-split-left'
1792
splitDropdownButton: {
1794
className: 'dt-btn-split-drop-button dt-button',
1798
className: 'dt-button-split-collection',
1808
Buttons.version = '2.2.2';
1811
$.extend( _dtButtons, {
1813
text: function ( dt ) {
1814
return dt.i18n( 'buttons.collection', 'Collection' );
1816
className: 'buttons-collection',
1818
init: function ( dt, button, config ) {
1819
button.attr( 'aria-expanded', false );
1821
action: function ( e, dt, button, config ) {
1822
if ( config._collection.parents('body').length ) {
1823
this.popover(false, config);
1826
this.popover(config._collection, config);
1830
'aria-haspopup': true
1835
text: function ( dt ) {
1836
return dt.i18n( 'buttons.split', 'Split' );
1838
className: 'buttons-split',
1840
init: function ( dt, button, config ) {
1841
return button.attr( 'aria-expanded', false );
1843
action: function ( e, dt, button, config ) {
1844
this.popover(config._collection, config);
1847
'aria-haspopup': true
1851
copy: function ( dt, conf ) {
1852
if ( _dtButtons.copyHtml5 ) {
1856
csv: function ( dt, conf ) {
1857
if ( _dtButtons.csvHtml5 && _dtButtons.csvHtml5.available( dt, conf ) ) {
1861
excel: function ( dt, conf ) {
1862
if ( _dtButtons.excelHtml5 && _dtButtons.excelHtml5.available( dt, conf ) ) {
1863
return 'excelHtml5';
1866
pdf: function ( dt, conf ) {
1867
if ( _dtButtons.pdfHtml5 && _dtButtons.pdfHtml5.available( dt, conf ) ) {
1871
pageLength: function ( dt ) {
1872
var lengthMenu = dt.settings()[0].aLengthMenu;
1875
var text = function ( dt ) {
1876
return dt.i18n( 'buttons.pageLength', {
1877
"-1": 'Show all rows',
1883
if (Array.isArray( lengthMenu[0] )) {
1884
vals = lengthMenu[0];
1885
lang = lengthMenu[1];
1888
for (var i=0 ; i<lengthMenu.length ; i++) {
1889
var option = lengthMenu[i];
1892
if ($.isPlainObject(option)) {
1893
vals.push(option.value);
1894
lang.push(option.label);
1904
extend: 'collection',
1906
className: 'buttons-page-length',
1908
buttons: $.map( vals, function ( val, i ) {
1911
className: 'button-page-length',
1912
action: function ( e, dt ) {
1913
dt.page.len( val ).draw();
1915
init: function ( dt, node, conf ) {
1917
var fn = function () {
1918
that.active( dt.page.len() === val );
1921
dt.on( 'length.dt'+conf.namespace, fn );
1924
destroy: function ( dt, node, conf ) {
1925
dt.off( 'length.dt'+conf.namespace );
1929
init: function ( dt, node, conf ) {
1931
dt.on( 'length.dt'+conf.namespace, function () {
1932
that.text( conf.text );
1935
destroy: function ( dt, node, conf ) {
1936
dt.off( 'length.dt'+conf.namespace );
1943
text: function ( dt ) {
1944
return dt.i18n( 'buttons.spacer', '' );
1958
DataTable.Api.register( 'buttons()', function ( group, selector ) {
1960
if ( selector === undefined ) {
1965
this.selector.buttonGroup = group;
1967
var res = this.iterator( true, 'table', function ( ctx ) {
1968
if ( ctx._buttons ) {
1969
return Buttons.buttonSelector(
1970
Buttons.instanceSelector( group, ctx._buttons ),
1976
res._groupSelector = group;
1981
DataTable.Api.register( 'button()', function ( group, selector ) {
1983
var buttons = this.buttons( group, selector );
1985
if ( buttons.length > 1 ) {
1986
buttons.splice( 1, buttons.length );
1993
DataTable.Api.registerPlural( 'buttons().active()', 'button().active()', function ( flag ) {
1994
if ( flag === undefined ) {
1995
return this.map( function ( set ) {
1996
return set.inst.active( set.node );
2000
return this.each( function ( set ) {
2001
set.inst.active( set.node, flag );
2006
DataTable.Api.registerPlural( 'buttons().action()', 'button().action()', function ( action ) {
2007
if ( action === undefined ) {
2008
return this.map( function ( set ) {
2009
return set.inst.action( set.node );
2013
return this.each( function ( set ) {
2014
set.inst.action( set.node, action );
2019
DataTable.Api.registerPlural( 'buttons().collectionRebuild()', 'button().collectionRebuild()', function ( buttons ) {
2020
return this.each( function ( set ) {
2021
for(var i = 0; i < buttons.length; i++) {
2022
if(typeof buttons[i] === 'object') {
2023
buttons[i].parentConf = set;
2026
set.inst.collectionRebuild( set.node, buttons );
2031
DataTable.Api.register( ['buttons().enable()', 'button().enable()'], function ( flag ) {
2032
return this.each( function ( set ) {
2033
set.inst.enable( set.node, flag );
2038
DataTable.Api.register( ['buttons().disable()', 'button().disable()'], function () {
2039
return this.each( function ( set ) {
2040
set.inst.disable( set.node );
2045
DataTable.Api.register( 'button().index()', function () {
2048
this.each( function ( set ) {
2049
var res = set.inst.index( set.node );
2060
DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function () {
2064
$( this.each( function ( set ) {
2065
jq = jq.add( set.inst.node( set.node ) );
2072
DataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {
2073
if ( flag === undefined ) {
2074
return this.map( function ( set ) {
2075
return set.inst.processing( set.node );
2079
return this.each( function ( set ) {
2080
set.inst.processing( set.node, flag );
2085
DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
2086
if ( label === undefined ) {
2087
return this.map( function ( set ) {
2088
return set.inst.text( set.node );
2092
return this.each( function ( set ) {
2093
set.inst.text( set.node, label );
2098
DataTable.Api.registerPlural( 'buttons().trigger()', 'button().trigger()', function () {
2099
return this.each( function ( set ) {
2100
set.inst.node( set.node ).trigger( 'click' );
2105
DataTable.Api.register( 'button().popover()', function (content, options) {
2106
return this.map( function ( set ) {
2107
return set.inst._popover( content, this.button(this[0].node), options );
2112
DataTable.Api.register( 'buttons().containers()', function () {
2114
var groupSelector = this._groupSelector;
2118
this.iterator( true, 'table', function ( ctx ) {
2119
if ( ctx._buttons ) {
2120
var insts = Buttons.instanceSelector( groupSelector, ctx._buttons );
2122
for ( var i=0, ien=insts.length ; i<ien ; i++ ) {
2123
jq = jq.add( insts[i].container() );
2131
DataTable.Api.register( 'buttons().container()', function () {
2133
return this.containers().eq(0);
2137
DataTable.Api.register( 'button().add()', function ( idx, conf, draw ) {
2138
var ctx = this.context;
2142
var inst = Buttons.instanceSelector( this._groupSelector, ctx[0]._buttons );
2144
if ( inst.length ) {
2145
inst[0].add( conf, idx , draw);
2149
return this.button( this._groupSelector, idx );
2153
DataTable.Api.register( 'buttons().destroy()', function () {
2154
this.pluck( 'inst' ).unique().each( function ( inst ) {
2162
DataTable.Api.registerPlural( 'buttons().remove()', 'buttons().remove()', function () {
2163
this.each( function ( set ) {
2164
set.inst.remove( set.node );
2172
DataTable.Api.register( 'buttons.info()', function ( title, message, time ) {
2175
if ( title === false ) {
2176
this.off('destroy.btn-info');
2178
$('#datatables_buttons_info'),
2184
clearTimeout( _infoTimer );
2191
clearTimeout( _infoTimer );
2194
if ( $('#datatables_buttons_info').length ) {
2195
$('#datatables_buttons_info').remove();
2198
title = title ? '<h2>'+title+'</h2>' : '';
2201
$('<div id="datatables_buttons_info" class="dt-button-info"/>')
2203
.append( $('<div/>')[ typeof message === 'string' ? 'html' : 'append' ]( message ) )
2204
.css( 'display', 'none' )
2208
if ( time !== undefined && time !== 0 ) {
2209
_infoTimer = setTimeout( function () {
2210
that.buttons.info( false );
2214
this.on('destroy.btn-info', function () {
2215
that.buttons.info(false);
2223
DataTable.Api.register( 'buttons.exportData()', function ( options ) {
2224
if ( this.context.length ) {
2225
return _exportData( new DataTable.Api( this.context[0] ), options );
2231
DataTable.Api.register( 'buttons.exportInfo()', function ( conf ) {
2237
filename: _filename( conf ),
2238
title: _title( conf ),
2239
messageTop: _message(this, conf.message || conf.messageTop, 'top'),
2240
messageBottom: _message(this, conf.messageBottom, 'bottom')
2252
var _filename = function ( config )
2255
var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined && config.title !== null && config.title !== '' ?
2259
if ( typeof filename === 'function' ) {
2260
filename = filename();
2263
if ( filename === undefined || filename === null ) {
2267
if ( filename.indexOf( '*' ) !== -1 ) {
2268
filename = filename.replace( '*', $('head > title').text() ).trim();
2272
filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
2274
var extension = _stringOrFunction( config.extension );
2275
if ( ! extension ) {
2279
return filename + extension;
2288
var _stringOrFunction = function ( option )
2290
if ( option === null || option === undefined ) {
2293
else if ( typeof option === 'function' ) {
2304
var _title = function ( config )
2306
var title = _stringOrFunction( config.title );
2308
return title === null ?
2309
null : title.indexOf( '*' ) !== -1 ?
2310
title.replace( '*', $('head > title').text() || 'Exported data' ) :
2314
var _message = function ( dt, option, position )
2316
var message = _stringOrFunction( option );
2317
if ( message === null ) {
2321
var caption = $('caption', dt.table().container()).eq(0);
2322
if ( message === '*' ) {
2323
var side = caption.css( 'caption-side' );
2324
if ( side !== position ) {
2328
return caption.length ?
2339
var _exportTextarea = $('<textarea/>')[0];
2340
var _exportData = function ( dt, inOpts )
2342
var config = $.extend( true, {}, {
2349
orthogonal: 'display',
2351
stripNewlines: true,
2352
decodeEntities: true,
2355
header: function ( d ) {
2356
return Buttons.stripData( d, config );
2358
footer: function ( d ) {
2359
return Buttons.stripData( d, config );
2361
body: function ( d ) {
2362
return Buttons.stripData( d, config );
2368
var header = dt.columns( config.columns ).indexes().map( function (idx) {
2369
var el = dt.column( idx ).header();
2370
return config.format.header( el.innerHTML, idx, el );
2373
var footer = dt.table().footer() ?
2374
dt.columns( config.columns ).indexes().map( function (idx) {
2375
var el = dt.column( idx ).footer();
2376
return config.format.footer( el ? el.innerHTML : '', idx, el );
2383
var modifier = $.extend( {}, config.modifier );
2384
if ( dt.select && typeof dt.select.info === 'function' && modifier.selected === undefined ) {
2385
if ( dt.rows( config.rows, $.extend( { selected: true }, modifier ) ).any() ) {
2386
$.extend( modifier, { selected: true } )
2390
var rowIndexes = dt.rows( config.rows, modifier ).indexes().toArray();
2391
var selectedCells = dt.cells( rowIndexes, config.columns );
2392
var cells = selectedCells
2393
.render( config.orthogonal )
2395
var cellNodes = selectedCells
2399
var columns = header.length;
2400
var rows = columns > 0 ? cells.length / columns : 0;
2402
var cellCounter = 0;
2404
for ( var i=0, ien=rows ; i<ien ; i++ ) {
2405
var row = [ columns ];
2407
for ( var j=0 ; j<columns ; j++ ) {
2408
row[j] = config.format.body( cells[ cellCounter ], i, j, cellNodes[ cellCounter ] );
2421
if ( config.customizeData ) {
2422
config.customizeData( data );
2434
$.fn.dataTable.Buttons = Buttons;
2435
$.fn.DataTable.Buttons = Buttons;
2444
$(document).on( 'init.dt plugin-init.dt', function (e, settings) {
2445
if ( e.namespace !== 'dt' ) {
2449
var opts = settings.oInit.buttons || DataTable.defaults.buttons;
2451
if ( opts && ! settings._buttons ) {
2452
new Buttons( settings, opts ).container();
2456
function _init ( settings, options ) {
2457
var api = new DataTable.Api( settings );
2460
: api.init().buttons || DataTable.defaults.buttons;
2462
return new Buttons( api, opts ).container();
2466
DataTable.ext.feature.push( {
2472
if ( DataTable.ext.features ) {
2473
DataTable.ext.features.register( 'buttons', _init );