Skip to content

Commit 649d7d8

Browse files
committed
New: File export buttons now have a processing indicator. Useful for tables with a long export time
New: `-api button().processing()` and `-api buttons().processing()` methods which can be used to programmatically enable and disable the button's processing state
1 parent 86aa7c2 commit 649d7d8

File tree

8 files changed

+293
-6
lines changed

8 files changed

+293
-6
lines changed

css/buttons.dataTables.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,8 @@ div.dt-button-background {
135135
}
136136

137137

138+
button.dt-button.processing,
139+
div.dt-button.processing,
140+
a.dt-button.processing {
141+
@include dtb-processing();
142+
}

css/mixins.scss

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,50 @@
8787
column-count: 4;
8888
}
8989
}
90+
91+
92+
@mixin dtb-processing {
93+
color: rgba(0, 0, 0, 0.2);
94+
95+
&:after {
96+
position: absolute;
97+
top: 50%;
98+
left: 50%;
99+
width: 16px;
100+
height: 16px;
101+
margin: -8px 0 0 -8px;
102+
box-sizing: border-box;
103+
104+
display: block;
105+
content: ' ';
106+
border: 2px solid rgb(40,40,40);
107+
border-radius: 50%;
108+
border-left-color: transparent;
109+
border-right-color: transparent;
110+
animation: cssload-spin 1500ms infinite linear;
111+
-o-animation: cssload-spin 1500ms infinite linear;
112+
-ms-animation: cssload-spin 1500ms infinite linear;
113+
-webkit-animation: cssload-spin 1500ms infinite linear;
114+
-moz-animation: cssload-spin 1500ms infinite linear;
115+
}
116+
117+
@keyframes cssload-spin {
118+
100%{ transform: rotate(360deg); transform: rotate(360deg); }
119+
}
120+
121+
@-o-keyframes cssload-spin {
122+
100%{ -o-transform: rotate(360deg); transform: rotate(360deg); }
123+
}
124+
125+
@-ms-keyframes cssload-spin {
126+
100%{ -ms-transform: rotate(360deg); transform: rotate(360deg); }
127+
}
128+
129+
@-webkit-keyframes cssload-spin {
130+
100%{ -webkit-transform: rotate(360deg); transform: rotate(360deg); }
131+
}
132+
133+
@-moz-keyframes cssload-spin {
134+
100%{ -moz-transform: rotate(360deg); transform: rotate(360deg); }
135+
}
136+
}

docs/api/button().processing().xml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<dt-api library="Buttons">
3+
<name>button().processing()</name>
4+
<summary>Get / set the processing state for a button</summary>
5+
<since>1.3.0</since>
6+
7+
<type type="function">
8+
<signature>button().processing()</signature>
9+
<returns type="boolean">
10+
`true` if the button is currently in its processing state, `false` otherwise.
11+
</returns>
12+
<description>
13+
Determine if a button is currently in the processing state or not.
14+
</description>
15+
</type>
16+
17+
<type type="function">
18+
<signature>button().processing( set )</signature>
19+
<parameter type="boolean" name="set">
20+
Flag to indicate if the processing state should be enabled (`true`) or disabled (`false`).
21+
</parameter>
22+
<returns type="DataTables.Api">
23+
DataTables API instance with the selected button in the result set, available for chaining further operations on the buttons.
24+
</returns>
25+
<description>
26+
Set the processing state for the selected button.
27+
</description>
28+
</type>
29+
30+
<description>
31+
Some actions that can be triggered by a button click can take a noticeable amount of time to complete - for example getting data from a server via an Ajax request, building a complex PDF document or any other asynchronous action. While the processing for that action is happening, it can be helpful to the end user to let them know that something is happening by showing a processing indicator. This method provides exactly that ability.
32+
33+
The typical use case will be to use `this.processing( true );` at the start of an action function and `that.processing( false );` inside a complete callback (where `that = this`).
34+
</description>
35+
36+
<example title="Show button index 1 as processing"><![CDATA[
37+
38+
var table = $('#myTable').DataTable();
39+
table.button( 1 ).processing( true );
40+
41+
]]></example>
42+
43+
<example title="Use the processing method inside an action function"><![CDATA[
44+
45+
var table = $('#myTable').DataTable();
46+
47+
table
48+
.button( 0 )
49+
.action( function () {
50+
this.processing( true );
51+
52+
// Do something...
53+
54+
this.processing( false );
55+
} );
56+
57+
]]></example>
58+
</dt-api>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<dt-api library="Buttons">
3+
<name>buttons().processing()</name>
4+
<summary>Set the processing state for multiple buttons</summary>
5+
<since>1.3.0</since>
6+
7+
<type type="function">
8+
<signature>buttons().processing( set )</signature>
9+
<parameter type="boolean" name="set">
10+
Flag to indicate if the processing state should be enabled (`true`) or disabled (`false`).
11+
</parameter>
12+
<returns type="DataTables.Api">
13+
DataTables API instance with the selected buttons in the result set, available for chaining further operations on the buttons.
14+
</returns>
15+
<description>
16+
Set the processing state for the selected buttons.
17+
</description>
18+
</type>
19+
20+
<description>
21+
This is an extension of the `-api buttons().processing()` method, which can be used to set the processing state for multiple buttons with a single API call. Care should be taken with this method since it could easily lead to end user confusion if multiple buttons are shown in the processing state at the same time.
22+
</description>
23+
24+
<example title="Set all buttons to show as processing"><![CDATA[
25+
26+
var table = $('#myTable').DataTable();
27+
table.buttons().processing( true );
28+
29+
]]></example>
30+
</dt-api>

js/buttons.flash.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,8 @@ DataTable.ext.buttons.copyFlash = $.extend( {}, flashButton, {
11511151
return;
11521152
}
11531153

1154+
this.processing( true );
1155+
11541156
var flash = config._flash;
11551157
var data = _exportData( dt, config );
11561158
var output = config.customize ?
@@ -1160,6 +1162,8 @@ DataTable.ext.buttons.copyFlash = $.extend( {}, flashButton, {
11601162
flash.setAction( 'copy' );
11611163
_setText( flash, output );
11621164

1165+
this.processing( false );
1166+
11631167
dt.buttons.info(
11641168
dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
11651169
dt.i18n( 'buttons.copySuccess', {
@@ -1208,6 +1212,8 @@ DataTable.ext.buttons.excelFlash = $.extend( {}, flashButton, {
12081212
},
12091213

12101214
action: function ( e, dt, button, config ) {
1215+
this.processing( true );
1216+
12111217
var flash = config._flash;
12121218
var rowPos = 0;
12131219
var rels = $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] ) ; //Parses xml
@@ -1372,6 +1378,8 @@ DataTable.ext.buttons.excelFlash = $.extend( {}, flashButton, {
13721378
flash.setFileName( _filename( config ) );
13731379
flash.setSheetData( xlsx );
13741380
_setText( flash, '' );
1381+
1382+
this.processing( false );
13751383
},
13761384

13771385
extension: '.xlsx'
@@ -1388,6 +1396,8 @@ DataTable.ext.buttons.pdfFlash = $.extend( {}, flashButton, {
13881396
},
13891397

13901398
action: function ( e, dt, button, config ) {
1399+
this.processing( true );
1400+
13911401
// Set the text
13921402
var flash = config._flash;
13931403
var data = dt.buttons.exportData( config.exportOptions );
@@ -1411,6 +1421,8 @@ DataTable.ext.buttons.pdfFlash = $.extend( {}, flashButton, {
14111421
footer: config.footer ? data.footer : null,
14121422
body: data.body
14131423
} ) );
1424+
1425+
this.processing( false );
14141426
},
14151427

14161428
extension: '.pdf',

js/buttons.html5.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,9 @@ DataTable.ext.buttons.copyHtml5 = {
827827
},
828828

829829
action: function ( e, dt, button, config ) {
830+
this.processing( true );
831+
832+
var that = this;
830833
var exportData = _exportData( dt, config );
831834
var output = exportData.str;
832835
var hiddenDiv = $('<div/>')
@@ -866,6 +869,8 @@ DataTable.ext.buttons.copyHtml5 = {
866869
}, exportData.rows ),
867870
2000
868871
);
872+
873+
this.processing( false );
869874
return;
870875
}
871876
}
@@ -899,10 +904,12 @@ DataTable.ext.buttons.copyHtml5 = {
899904
.on( 'keydown.buttons-copy', function (e) {
900905
if ( e.keyCode === 27 ) { // esc
901906
close();
907+
that.processing( false );
902908
}
903909
} )
904910
.on( 'copy.buttons-copy cut.buttons-copy', function () {
905911
close();
912+
that.processing( false );
906913
} );
907914
},
908915

@@ -934,6 +941,8 @@ DataTable.ext.buttons.csvHtml5 = {
934941
},
935942

936943
action: function ( e, dt, button, config ) {
944+
this.processing( true );
945+
937946
// Set the text
938947
var output = _exportData( dt, config ).str;
939948
var charset = config.charset;
@@ -964,6 +973,8 @@ DataTable.ext.buttons.csvHtml5 = {
964973
_filename( config ),
965974
true
966975
);
976+
977+
this.processing( false );
967978
},
968979

969980
filename: '*',
@@ -1000,6 +1011,9 @@ DataTable.ext.buttons.excelHtml5 = {
10001011
},
10011012

10021013
action: function ( e, dt, button, config ) {
1014+
this.processing( true );
1015+
1016+
var that = this;
10031017
var rowPos = 0;
10041018
var getXml = function ( type ) {
10051019
var str = excelStrings[ type ];
@@ -1179,6 +1193,7 @@ DataTable.ext.buttons.excelHtml5 = {
11791193
.generateAsync( zipConfig )
11801194
.then( function ( blob ) {
11811195
_saveAs( blob, _filename( config ) );
1196+
that.processing( false );
11821197
} );
11831198
}
11841199
else {
@@ -1187,6 +1202,7 @@ DataTable.ext.buttons.excelHtml5 = {
11871202
zip.generate( zipConfig ),
11881203
_filename( config )
11891204
);
1205+
this.processing( false );
11901206
}
11911207
},
11921208

@@ -1216,7 +1232,9 @@ DataTable.ext.buttons.pdfHtml5 = {
12161232
},
12171233

12181234
action: function ( e, dt, button, config ) {
1219-
var newLine = _newLine( config );
1235+
this.processing( true );
1236+
1237+
var that = this;
12201238
var data = dt.buttons.exportData( config.exportOptions );
12211239
var rows = [];
12221240

@@ -1289,11 +1307,11 @@ DataTable.ext.buttons.pdfHtml5 = {
12891307
};
12901308

12911309
if ( config.message ) {
1292-
doc.content.unshift( {
1293-
text: typeof config.message == 'function' ? config.message(dt, button, config) : config.message,
1294-
style: 'message',
1295-
margin: [ 0, 0, 0, 12 ]
1296-
} );
1310+
doc.content.unshift( {
1311+
text: typeof config.message == 'function' ? config.message(dt, button, config) : config.message,
1312+
style: 'message',
1313+
margin: [ 0, 0, 0, 12 ]
1314+
} );
12971315
}
12981316

12991317
if ( config.title ) {
@@ -1312,12 +1330,14 @@ DataTable.ext.buttons.pdfHtml5 = {
13121330

13131331
if ( config.download === 'open' && ! _isDuffSafari() ) {
13141332
pdf.open();
1333+
this.processing( false );
13151334
}
13161335
else {
13171336
pdf.getBuffer( function (buffer) {
13181337
var blob = new Blob( [buffer], {type:'application/pdf'} );
13191338

13201339
_saveAs( blob, _filename( config ) );
1340+
that.processing( false );
13211341
} );
13221342
}
13231343
},

js/dataTables.buttons.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,24 @@ $.extend( Buttons.prototype, {
258258
return $(button.node);
259259
},
260260

261+
/**
262+
* Set / get a processing class on the selected button
263+
* @param {boolean} flag true to add, false to remove, undefined to get
264+
* @return {boolean|Buttons} Getter value or this if a setter.
265+
*/
266+
processing: function ( node, flag )
267+
{
268+
var button = this._nodeToButton( node );
269+
270+
if ( flag === undefined ) {
271+
return $(button.node).hasClass( 'processing' );
272+
}
273+
274+
$(button.node).toggleClass( 'processing', flag );
275+
276+
return this;
277+
},
278+
261279
/**
262280
* Remove a button.
263281
* @param {node} node Button node
@@ -1405,6 +1423,19 @@ DataTable.Api.registerPlural( 'buttons().nodes()', 'button().node()', function (
14051423
return jq;
14061424
} );
14071425

1426+
// Get / set button processing state
1427+
DataTable.Api.registerPlural( 'buttons().processing()', 'button().processing()', function ( flag ) {
1428+
if ( flag === undefined ) {
1429+
return this.map( function ( set ) {
1430+
return set.inst.processing( set.node );
1431+
} );
1432+
}
1433+
1434+
return this.each( function ( set ) {
1435+
set.inst.processing( set.node, flag );
1436+
} );
1437+
} );
1438+
14081439
// Get / set button text (i.e. the button labels)
14091440
DataTable.Api.registerPlural( 'buttons().text()', 'button().text()', function ( label ) {
14101441
if ( label === undefined ) {

0 commit comments

Comments
 (0)