jquery-datatables 1.10.12 → 1.10.13

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/app/assets/javascripts/datatables/dataTables.bootstrap.js +2 -2
  4. data/app/assets/javascripts/datatables/dataTables.bootstrap4.js +5 -5
  5. data/app/assets/javascripts/datatables/dataTables.foundation.js +1 -1
  6. data/app/assets/javascripts/datatables/dataTables.material.js +1 -1
  7. data/app/assets/javascripts/datatables/dataTables.semanticui.js +1 -1
  8. data/app/assets/javascripts/datatables/extensions/AutoFill/dataTables.autoFill.js +63 -31
  9. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.colVis.js +2 -3
  10. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.flash.js +145 -55
  11. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.html5.js +224 -206
  12. data/app/assets/javascripts/datatables/extensions/Buttons/buttons.print.js +14 -8
  13. data/app/assets/javascripts/datatables/extensions/Buttons/dataTables.buttons.js +54 -24
  14. data/app/assets/javascripts/datatables/extensions/KeyTable/dataTables.keyTable.js +137 -68
  15. data/app/assets/javascripts/datatables/extensions/Responsive/dataTables.responsive.js +30 -7
  16. data/app/assets/javascripts/datatables/extensions/Responsive/responsive.bootstrap.js +6 -2
  17. data/app/assets/javascripts/datatables/extensions/Responsive/responsive.bootstrap4.js +6 -2
  18. data/app/assets/javascripts/datatables/extensions/RowReorder/dataTables.rowReorder.js +64 -6
  19. data/app/assets/javascripts/datatables/extensions/Select/dataTables.select.js +40 -15
  20. data/app/assets/javascripts/datatables/jquery.dataTables.js +246 -217
  21. data/app/assets/javascripts/datatables/plugins/api/average.js +32 -0
  22. data/app/assets/javascripts/datatables/plugins/api/sum.js +51 -0
  23. data/app/assets/javascripts/datatables/plugins/pagination/input.js +224 -0
  24. data/app/assets/javascripts/datatables/plugins/search/alphabetSearch.js +368 -0
  25. data/app/assets/javascripts/datatables/plugins/sorting/file-size.js +43 -0
  26. data/app/assets/javascripts/datatables/plugins/sorting/ip-address.js +103 -0
  27. data/app/assets/stylesheets/datatables/dataTables.bootstrap.css +0 -1
  28. data/app/assets/stylesheets/datatables/dataTables.semanticui.css +0 -1
  29. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.bootstrap.css +4 -4
  30. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.bootstrap4.css +4 -4
  31. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.dataTables.css +4 -4
  32. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.foundation.css +4 -4
  33. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.jqueryui.css +4 -4
  34. data/app/assets/stylesheets/datatables/extensions/Responsive/responsive.semanticui.css +4 -4
  35. data/app/assets/stylesheets/datatables/extensions/Select/select.bootstrap.css +9 -4
  36. data/app/assets/stylesheets/datatables/extensions/Select/select.bootstrap4.css +9 -4
  37. data/app/assets/stylesheets/datatables/extensions/Select/select.dataTables.css +9 -4
  38. data/app/assets/stylesheets/datatables/extensions/Select/select.foundation.css +9 -4
  39. data/app/assets/stylesheets/datatables/extensions/Select/select.jqueryui.css +9 -4
  40. data/app/assets/stylesheets/datatables/extensions/Select/select.semanticui.css +9 -4
  41. data/app/assets/stylesheets/datatables/plugins/search/alphabetSearch.css +43 -0
  42. data/lib/jquery-datatables/version.rb +1 -1
  43. metadata +10 -3
@@ -2,7 +2,7 @@
2
2
  * HTML5 export buttons for Buttons and DataTables.
3
3
  * 2016 SpryMedia Ltd - datatables.net/license
4
4
  *
5
- * FileSaver.js (1.1.20160328) - MIT license
5
+ * FileSaver.js (1.3.3) - MIT license
6
6
  * Copyright © 2016 Eli Grey - http://eligrey.com
7
7
  */
8
8
 
@@ -35,17 +35,17 @@
35
35
  // Browser
36
36
  factory( jQuery, window, document );
37
37
  }
38
- }(function( $, window, document, jsZip, pdfMake, undefined ) {
38
+ }(function( $, window, document, jszip, pdfmake, undefined ) {
39
39
  'use strict';
40
40
  var DataTable = $.fn.dataTable;
41
41
 
42
42
  // Allow the constructor to pass in JSZip and PDFMake from external requires.
43
43
  // Otherwise, use globally defined variables, if they are available.
44
- if ( jsZip === undefined ) {
45
- jsZip = window.JSZip;
44
+ function _jsZip () {
45
+ return jszip || window.JSZip;
46
46
  }
47
- if ( pdfMake === undefined ) {
48
- pdfMake = window.pdfMake;
47
+ function _pdfMake () {
48
+ return pdfmake || window.pdfMake;
49
49
  }
50
50
 
51
51
 
@@ -58,7 +58,7 @@ if ( pdfMake === undefined ) {
58
58
  var _saveAs = (function(view) {
59
59
  "use strict";
60
60
  // IE <10 is explicitly unsupported
61
- if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
61
+ if (typeof view === "undefined" || typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
62
62
  return;
63
63
  }
64
64
  var
@@ -73,16 +73,14 @@ var _saveAs = (function(view) {
73
73
  var event = new MouseEvent("click");
74
74
  node.dispatchEvent(event);
75
75
  }
76
- , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent)
77
- , webkit_req_fs = view.webkitRequestFileSystem
78
- , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
76
+ , is_safari = /constructor/i.test(view.HTMLElement) || view.safari
77
+ , is_chrome_ios =/CriOS\/[\d]+/.test(navigator.userAgent)
79
78
  , throw_outside = function(ex) {
80
79
  (view.setImmediate || view.setTimeout)(function() {
81
80
  throw ex;
82
81
  }, 0);
83
82
  }
84
83
  , force_saveable_type = "application/octet-stream"
85
- , fs_min_size = 0
86
84
  // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
87
85
  , arbitrary_revoke_timeout = 1000 * 40 // in ms
88
86
  , revoke = function(file) {
@@ -93,22 +91,6 @@ var _saveAs = (function(view) {
93
91
  file.remove();
94
92
  }
95
93
  };
96
- /* // Take note W3C:
97
- var
98
- uri = typeof file === "string" ? file : file.toURL()
99
- , revoker = function(evt) {
100
- // idealy DownloadFinishedEvent.data would be the URL requested
101
- if (evt.data === uri) {
102
- if (typeof file === "string") { // file is an object URL
103
- get_URL().revokeObjectURL(file);
104
- } else { // file is a File
105
- file.remove();
106
- }
107
- }
108
- }
109
- ;
110
- view.addEventListener("downloadfinished", revoker);
111
- */
112
94
  setTimeout(revoker, arbitrary_revoke_timeout);
113
95
  }
114
96
  , dispatch = function(filesaver, event_types, event) {
@@ -127,8 +109,9 @@ var _saveAs = (function(view) {
127
109
  }
128
110
  , auto_bom = function(blob) {
129
111
  // prepend BOM for UTF-8 XML and text/* types (including HTML)
112
+ // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
130
113
  if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
131
- return new Blob(["\ufeff", blob], {type: blob.type});
114
+ return new Blob([String.fromCharCode(0xFEFF), blob], {type: blob.type});
132
115
  }
133
116
  return blob;
134
117
  }
@@ -140,20 +123,21 @@ var _saveAs = (function(view) {
140
123
  var
141
124
  filesaver = this
142
125
  , type = blob.type
143
- , blob_changed = false
126
+ , force = type === force_saveable_type
144
127
  , object_url
145
- , target_view
146
128
  , dispatch_all = function() {
147
129
  dispatch(filesaver, "writestart progress write writeend".split(" "));
148
130
  }
149
131
  // on any filesys errors revert to saving with object URLs
150
132
  , fs_error = function() {
151
- if (target_view && is_safari && typeof FileReader !== "undefined") {
133
+ if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {
152
134
  // Safari doesn't allow downloading of blob urls
153
135
  var reader = new FileReader();
154
136
  reader.onloadend = function() {
155
- var base64Data = reader.result;
156
- target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
137
+ var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');
138
+ var popup = view.open(url, '_blank');
139
+ if(!popup) view.location.href = url;
140
+ url=undefined; // release reference before dispatching
157
141
  filesaver.readyState = filesaver.DONE;
158
142
  dispatch_all();
159
143
  };
@@ -162,36 +146,25 @@ var _saveAs = (function(view) {
162
146
  return;
163
147
  }
164
148
  // don't create more object URLs than needed
165
- if (blob_changed || !object_url) {
149
+ if (!object_url) {
166
150
  object_url = get_URL().createObjectURL(blob);
167
151
  }
168
- if (target_view) {
169
- target_view.location.href = object_url;
152
+ if (force) {
153
+ view.location.href = object_url;
170
154
  } else {
171
- var new_tab = view.open(object_url, "_blank");
172
- if (new_tab === undefined && is_safari) {
173
- //Apple do not allow window.open, see http://bit.ly/1kZffRI
174
- view.location.href = object_url
155
+ var opened = view.open(object_url, "_blank");
156
+ if (!opened) {
157
+ // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html
158
+ view.location.href = object_url;
175
159
  }
176
160
  }
177
161
  filesaver.readyState = filesaver.DONE;
178
162
  dispatch_all();
179
163
  revoke(object_url);
180
164
  }
181
- , abortable = function(func) {
182
- return function() {
183
- if (filesaver.readyState !== filesaver.DONE) {
184
- return func.apply(this, arguments);
185
- }
186
- };
187
- }
188
- , create_if_not_found = {create: true, exclusive: false}
189
- , slice
190
165
  ;
191
166
  filesaver.readyState = filesaver.INIT;
192
- if (!name) {
193
- name = "download";
194
- }
167
+
195
168
  if (can_use_save_link) {
196
169
  object_url = get_URL().createObjectURL(blob);
197
170
  setTimeout(function() {
@@ -204,93 +177,27 @@ var _saveAs = (function(view) {
204
177
  });
205
178
  return;
206
179
  }
207
- // Object and web filesystem URLs have a problem saving in Google Chrome when
208
- // viewed in a tab, so I force save with application/octet-stream
209
- // http://code.google.com/p/chromium/issues/detail?id=91158
210
- // Update: Google errantly closed 91158, I submitted it again:
211
- // https://code.google.com/p/chromium/issues/detail?id=389642
212
- if (view.chrome && type && type !== force_saveable_type) {
213
- slice = blob.slice || blob.webkitSlice;
214
- blob = slice.call(blob, 0, blob.size, force_saveable_type);
215
- blob_changed = true;
216
- }
217
- // Since I can't be sure that the guessed media type will trigger a download
218
- // in WebKit, I append .download to the filename.
219
- // https://bugs.webkit.org/show_bug.cgi?id=65440
220
- if (webkit_req_fs && name !== "download") {
221
- name += ".download";
222
- }
223
- if (type === force_saveable_type || webkit_req_fs) {
224
- target_view = view;
225
- }
226
- if (!req_fs) {
227
- fs_error();
228
- return;
229
- }
230
- fs_min_size += blob.size;
231
- req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
232
- fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
233
- var save = function() {
234
- dir.getFile(name, create_if_not_found, abortable(function(file) {
235
- file.createWriter(abortable(function(writer) {
236
- writer.onwriteend = function(event) {
237
- target_view.location.href = file.toURL();
238
- filesaver.readyState = filesaver.DONE;
239
- dispatch(filesaver, "writeend", event);
240
- revoke(file);
241
- };
242
- writer.onerror = function() {
243
- var error = writer.error;
244
- if (error.code !== error.ABORT_ERR) {
245
- fs_error();
246
- }
247
- };
248
- "writestart progress write abort".split(" ").forEach(function(event) {
249
- writer["on" + event] = filesaver["on" + event];
250
- });
251
- writer.write(blob);
252
- filesaver.abort = function() {
253
- writer.abort();
254
- filesaver.readyState = filesaver.DONE;
255
- };
256
- filesaver.readyState = filesaver.WRITING;
257
- }), fs_error);
258
- }), fs_error);
259
- };
260
- dir.getFile(name, {create: false}, abortable(function(file) {
261
- // delete file if it already exists
262
- file.remove();
263
- save();
264
- }), abortable(function(ex) {
265
- if (ex.code === ex.NOT_FOUND_ERR) {
266
- save();
267
- } else {
268
- fs_error();
269
- }
270
- }));
271
- }), fs_error);
272
- }), fs_error);
180
+
181
+ fs_error();
273
182
  }
274
183
  , FS_proto = FileSaver.prototype
275
184
  , saveAs = function(blob, name, no_auto_bom) {
276
- return new FileSaver(blob, name, no_auto_bom);
185
+ return new FileSaver(blob, name || blob.name || "download", no_auto_bom);
277
186
  }
278
187
  ;
279
188
  // IE 10+ (native saveAs)
280
189
  if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
281
190
  return function(blob, name, no_auto_bom) {
191
+ name = name || blob.name || "download";
192
+
282
193
  if (!no_auto_bom) {
283
194
  blob = auto_bom(blob);
284
195
  }
285
- return navigator.msSaveOrOpenBlob(blob, name || "download");
196
+ return navigator.msSaveOrOpenBlob(blob, name);
286
197
  };
287
198
  }
288
199
 
289
- FS_proto.abort = function() {
290
- var filesaver = this;
291
- filesaver.readyState = filesaver.DONE;
292
- dispatch(filesaver, "abort");
293
- };
200
+ FS_proto.abort = function(){};
294
201
  FS_proto.readyState = FS_proto.INIT = 0;
295
202
  FS_proto.WRITING = 1;
296
203
  FS_proto.DONE = 2;
@@ -450,17 +357,27 @@ var _exportData = function ( dt, config )
450
357
  };
451
358
 
452
359
  /**
453
- * Safari's data: support for creating and downloading files is really poor, so
454
- * various options need to be disabled in it. See
455
- * https://bugs.webkit.org/show_bug.cgi?id=102914
360
+ * Older versions of Safari (prior to tech preview 18) don't support the
361
+ * download option required.
456
362
  *
457
- * @return {Boolean} `true` if Safari
363
+ * @return {Boolean} `true` if old Safari
458
364
  */
459
- var _isSafari = function ()
365
+ var _isDuffSafari = function ()
460
366
  {
461
- return navigator.userAgent.indexOf('Safari') !== -1 &&
367
+ var safari = navigator.userAgent.indexOf('Safari') !== -1 &&
462
368
  navigator.userAgent.indexOf('Chrome') === -1 &&
463
369
  navigator.userAgent.indexOf('Opera') === -1;
370
+
371
+ if ( ! safari ) {
372
+ return false;
373
+ }
374
+
375
+ var version = navigator.userAgent.match( /AppleWebKit\/(\d+\.\d+)/ );
376
+ if ( version && version.length > 1 && version[1]*1 < 603.1 ) {
377
+ return true;
378
+ }
379
+
380
+ return false;
464
381
  };
465
382
 
466
383
  /**
@@ -554,11 +471,9 @@ function _addToZip( zip, obj ) {
554
471
  str = str.replace( /_dt_b_namespace_token_/g, ':' );
555
472
  }
556
473
 
557
- // Both IE and Edge will put empty name space attributes onto the
558
- // rows and columns making them useless
559
- str = str
560
- .replace( /<row xmlns="" /g, '<row ' )
561
- .replace( /<cols xmlns="">/g, '<cols>' );
474
+ // Safari, IE and Edge will put empty name space attributes onto
475
+ // various elements making them useless. This strips them out
476
+ str = str.replace( /<(.*?) xmlns=""(.*?)>/g, '<$1 $2>' );
562
477
 
563
478
  zip.file( name, str );
564
479
  }
@@ -605,14 +520,28 @@ function _createNode( doc, nodeName, opts ) {
605
520
  */
606
521
  function _excelColWidth( data, col ) {
607
522
  var max = data.header[col].length;
608
- var len;
523
+ var len, lineSplit, str;
609
524
 
610
525
  if ( data.footer && data.footer[col].length > max ) {
611
526
  max = data.footer[col].length;
612
527
  }
613
528
 
614
529
  for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
615
- len = data.body[i][col].toString().length;
530
+ str = data.body[i][col].toString();
531
+
532
+ // If there is a newline character, workout the width of the column
533
+ // based on the longest line in the string
534
+ if ( str.indexOf('\n') !== -1 ) {
535
+ lineSplit = str.split('\n');
536
+ lineSplit.sort( function (a, b) {
537
+ return b.length - a.length;
538
+ } );
539
+
540
+ len = lineSplit[0].length;
541
+ }
542
+ else {
543
+ len = str.length;
544
+ }
616
545
 
617
546
  if ( len > max ) {
618
547
  max = len;
@@ -624,8 +553,10 @@ function _excelColWidth( data, col ) {
624
553
  }
625
554
  }
626
555
 
556
+ max *= 1.3;
557
+
627
558
  // And a min width
628
- return max > 5 ? max : 5;
559
+ return max > 6 ? max : 6;
629
560
  }
630
561
 
631
562
  // Excel - Pre-defined strings to build a basic XLSX file
@@ -673,9 +604,17 @@ var excelStrings = {
673
604
  '<sheetData/>'+
674
605
  '</worksheet>',
675
606
 
676
- "xl/styles.xml":
607
+ "xl/styles.xml":
677
608
  '<?xml version="1.0" encoding="UTF-8"?>'+
678
609
  '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+
610
+ '<numFmts count="6">'+
611
+ '<numFmt numFmtId="164" formatCode="#,##0.00_-\ [$$-45C]"/>'+
612
+ '<numFmt numFmtId="165" formatCode="&quot;£&quot;#,##0.00"/>'+
613
+ '<numFmt numFmtId="166" formatCode="[$€-2]\ #,##0.00"/>'+
614
+ '<numFmt numFmtId="167" formatCode="0.0%"/>'+
615
+ '<numFmt numFmtId="168" formatCode="#,##0;(#,##0)"/>'+
616
+ '<numFmt numFmtId="169" formatCode="#,##0.00;(#,##0.00)"/>'+
617
+ '</numFmts>'+
679
618
  '<fonts count="5" x14ac:knownFonts="1">'+
680
619
  '<font>'+
681
620
  '<sz val="11" />'+
@@ -759,7 +698,7 @@ var excelStrings = {
759
698
  '<cellStyleXfs count="1">'+
760
699
  '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />'+
761
700
  '</cellStyleXfs>'+
762
- '<cellXfs count="2">'+
701
+ '<cellXfs count="65">'+
763
702
  '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
764
703
  '<xf numFmtId="0" fontId="1" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
765
704
  '<xf numFmtId="0" fontId="2" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
@@ -810,6 +749,33 @@ var excelStrings = {
810
749
  '<xf numFmtId="0" fontId="2" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
811
750
  '<xf numFmtId="0" fontId="3" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
812
751
  '<xf numFmtId="0" fontId="4" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
752
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
753
+ '<alignment horizontal="left"/>'+
754
+ '</xf>'+
755
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
756
+ '<alignment horizontal="center"/>'+
757
+ '</xf>'+
758
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
759
+ '<alignment horizontal="right"/>'+
760
+ '</xf>'+
761
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
762
+ '<alignment horizontal="fill"/>'+
763
+ '</xf>'+
764
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
765
+ '<alignment textRotation="90"/>'+
766
+ '</xf>'+
767
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
768
+ '<alignment wrapText="1"/>'+
769
+ '</xf>'+
770
+ '<xf numFmtId="9" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
771
+ '<xf numFmtId="164" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
772
+ '<xf numFmtId="165" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
773
+ '<xf numFmtId="166" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
774
+ '<xf numFmtId="167" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
775
+ '<xf numFmtId="168" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
776
+ '<xf numFmtId="169" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
777
+ '<xf numFmtId="3" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
778
+ '<xf numFmtId="4" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyNumberFormat="1"/>'+
813
779
  '</cellXfs>'+
814
780
  '<cellStyles count="1">'+
815
781
  '<cellStyle name="Normal" xfId="0" builtinId="0" />'+
@@ -821,6 +787,22 @@ var excelStrings = {
821
787
  // Note we could use 3 `for` loops for the styles, but when gzipped there is
822
788
  // virtually no difference in size, since the above can be easily compressed
823
789
 
790
+ // Pattern matching for special number formats. Perhaps this should be exposed
791
+ // via an API in future?
792
+ // Ref: section 3.8.30 - built in formatters in open spreadsheet
793
+ // https://www.ecma-international.org/news/TC45_current_work/Office%20Open%20XML%20Part%204%20-%20Markup%20Language%20Reference.pdf
794
+ var _excelSpecials = [
795
+ { match: /^\-?\d+\.\d%$/, style: 60, fmt: function (d) { return d/100; } }, // Precent with d.p.
796
+ { match: /^\-?\d+\.?\d*%$/, style: 56, fmt: function (d) { return d/100; } }, // Percent
797
+ { match: /^\-?\$[\d,]+.?\d*$/, style: 57 }, // Dollars
798
+ { match: /^\-?£[\d,]+.?\d*$/, style: 58 }, // Pounds
799
+ { match: /^\-?€[\d,]+.?\d*$/, style: 59 }, // Euros
800
+ { match: /^\([\d,]+\)$/, style: 61, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets
801
+ { match: /^\([\d,]+\.\d{2}\)$/, style: 62, fmt: function (d) { return -1 * d.replace(/[\(\)]/g, ''); } }, // Negative numbers indicated by brackets - 2d.p.
802
+ { match: /^[\d,]+$/, style: 63 }, // Numbers with thousand separators
803
+ { match: /^[\d,]+\.\d{2}$/, style: 64 } // Numbers with 2d.p. and thousands separators
804
+ ];
805
+
824
806
 
825
807
 
826
808
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@ -865,19 +847,20 @@ DataTable.ext.buttons.copyHtml5 = {
865
847
  textarea[0].select();
866
848
 
867
849
  try {
868
- document.execCommand( 'copy' );
850
+ var successful = document.execCommand( 'copy' );
869
851
  hiddenDiv.remove();
870
852
 
871
- dt.buttons.info(
872
- dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
873
- dt.i18n( 'buttons.copySuccess', {
874
- 1: "Copied one row to clipboard",
875
- _: "Copied %d rows to clipboard"
853
+ if (successful) {
854
+ dt.buttons.info(
855
+ dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
856
+ dt.i18n( 'buttons.copySuccess', {
857
+ 1: 'Copied one row to clipboard',
858
+ _: 'Copied %d rows to clipboard'
876
859
  }, exportData.rows ),
877
- 2000
878
- );
879
-
880
- return;
860
+ 2000
861
+ );
862
+ return;
863
+ }
881
864
  }
882
865
  catch (t) {}
883
866
  }
@@ -931,6 +914,8 @@ DataTable.ext.buttons.copyHtml5 = {
931
914
  // CSV export
932
915
  //
933
916
  DataTable.ext.buttons.csvHtml5 = {
917
+ bom: false,
918
+
934
919
  className: 'buttons-csv buttons-html5',
935
920
 
936
921
  available: function () {
@@ -963,9 +948,14 @@ DataTable.ext.buttons.csvHtml5 = {
963
948
  charset = '';
964
949
  }
965
950
 
951
+ if ( config.bom ) {
952
+ output = '\ufeff' + output;
953
+ }
954
+
966
955
  _saveAs(
967
956
  new Blob( [output], {type: 'text/csv'+charset} ),
968
- _filename( config )
957
+ _filename( config ),
958
+ true
969
959
  );
970
960
  },
971
961
 
@@ -995,7 +985,7 @@ DataTable.ext.buttons.excelHtml5 = {
995
985
  className: 'buttons-excel buttons-html5',
996
986
 
997
987
  available: function () {
998
- return window.FileReader !== undefined && jsZip !== undefined && ! _isSafari() && _serialiser;
988
+ return window.FileReader !== undefined && _jsZip() !== undefined && ! _isDuffSafari() && _serialiser;
999
989
  },
1000
990
 
1001
991
  text: function ( dt ) {
@@ -1041,58 +1031,85 @@ DataTable.ext.buttons.excelHtml5 = {
1041
1031
  for ( var i=0, ien=row.length ; i<ien ; i++ ) {
1042
1032
  // Concat both the Cell Columns as a letter and the Row of the cell.
1043
1033
  var cellId = createCellPos(i) + '' + currentRow;
1044
- var cell;
1034
+ var cell = null;
1045
1035
 
1046
- if ( row[i] === null || row[i] === undefined ) {
1047
- row[i] = '';
1036
+ // For null, undefined of blank cell, continue so it doesn't create the _createNode
1037
+ if ( row[i] === null || row[i] === undefined || row[i] === '' ) {
1038
+ continue;
1048
1039
  }
1049
1040
 
1050
- // Detect numbers - don't match numbers with leading zeros or a negative
1051
- // anywhere but the start
1052
- if ( typeof row[i] === 'number' || (
1053
- row[i].match &&
1054
- $.trim(row[i]).match(/^-?\d+(\.\d+)?$/) &&
1055
- ! $.trim(row[i]).match(/^0\d+/) )
1056
- ) {
1057
- cell = _createNode( rels, 'c', {
1058
- attr: {
1059
- t: 'n',
1060
- r: cellId
1061
- },
1062
- children: [
1063
- _createNode( rels, 'v', { text: row[i] } )
1064
- ]
1065
- } );
1066
- }
1067
- else {
1068
- // Replace non standard characters for text output
1069
- var text = ! row[i].replace ?
1070
- row[i] :
1071
- row[i]
1072
- .replace(/&(?!amp;)/g, '&amp;')
1073
- .replace(/</g, '&lt;')
1074
- .replace(/>/g, '&gt;')
1075
- .replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
1076
-
1077
- cell = _createNode( rels, 'c', {
1078
- attr: {
1079
- t: 'inlineStr',
1080
- r: cellId
1081
- },
1082
- children:{
1083
- row: _createNode( rels, 'is', {
1084
- children: {
1085
- row: _createNode( rels, 't', {
1086
- text: text
1087
- } )
1088
- }
1089
- } )
1041
+ row[i] = $.trim( row[i] );
1042
+
1043
+ // Special number formatting options
1044
+ for ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {
1045
+ var special = _excelSpecials[j];
1046
+
1047
+ if ( row[i].match && row[i].match( special.match ) ) {
1048
+ var val = row[i].replace(/[^\d\.\-]/g, '');
1049
+
1050
+ if ( special.fmt ) {
1051
+ val = special.fmt( val );
1090
1052
  }
1091
- } );
1053
+
1054
+ cell = _createNode( rels, 'c', {
1055
+ attr: {
1056
+ r: cellId,
1057
+ s: special.style
1058
+ },
1059
+ children: [
1060
+ _createNode( rels, 'v', { text: val } )
1061
+ ]
1062
+ } );
1063
+
1064
+ break;
1065
+ }
1066
+ }
1067
+
1068
+ if ( ! cell ) {
1069
+ if ( typeof row[i] === 'number' || (
1070
+ row[i].match &&
1071
+ row[i].match(/^-?\d+(\.\d+)?$/) &&
1072
+ ! row[i].match(/^0\d+/) )
1073
+ ) {
1074
+ // Detect numbers - don't match numbers with leading zeros
1075
+ // or a negative anywhere but the start
1076
+ cell = _createNode( rels, 'c', {
1077
+ attr: {
1078
+ t: 'n',
1079
+ r: cellId
1080
+ },
1081
+ children: [
1082
+ _createNode( rels, 'v', { text: row[i] } )
1083
+ ]
1084
+ } );
1085
+ }
1086
+ else {
1087
+ // String output - replace non standard characters for text output
1088
+ var text = ! row[i].replace ?
1089
+ row[i] :
1090
+ row[i].replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
1091
+
1092
+ cell = _createNode( rels, 'c', {
1093
+ attr: {
1094
+ t: 'inlineStr',
1095
+ r: cellId
1096
+ },
1097
+ children:{
1098
+ row: _createNode( rels, 'is', {
1099
+ children: {
1100
+ row: _createNode( rels, 't', {
1101
+ text: text
1102
+ } )
1103
+ }
1104
+ } )
1105
+ }
1106
+ } );
1107
+ }
1092
1108
  }
1093
1109
 
1094
1110
  rowNode.appendChild( cell );
1095
1111
  }
1112
+
1096
1113
  relsGet.appendChild(rowNode);
1097
1114
  rowPos++;
1098
1115
  };
@@ -1137,7 +1154,8 @@ DataTable.ext.buttons.excelHtml5 = {
1137
1154
  config.customize( xlsx );
1138
1155
  }
1139
1156
 
1140
- var zip = new jsZip();
1157
+ var jszip = _jsZip();
1158
+ var zip = new jszip();
1141
1159
  var zipConfig = {
1142
1160
  type: 'blob',
1143
1161
  mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
@@ -1180,7 +1198,7 @@ DataTable.ext.buttons.pdfHtml5 = {
1180
1198
  className: 'buttons-pdf buttons-html5',
1181
1199
 
1182
1200
  available: function () {
1183
- return window.FileReader !== undefined && pdfMake;
1201
+ return window.FileReader !== undefined && _pdfMake();
1184
1202
  },
1185
1203
 
1186
1204
  text: function ( dt ) {
@@ -1261,11 +1279,11 @@ DataTable.ext.buttons.pdfHtml5 = {
1261
1279
  };
1262
1280
 
1263
1281
  if ( config.message ) {
1264
- doc.content.unshift( {
1265
- text: config.message,
1266
- style: 'message',
1267
- margin: [ 0, 0, 0, 12 ]
1268
- } );
1282
+ doc.content.unshift( {
1283
+ text: typeof config.message == 'function' ? config.message(dt, button, config) : config.message,
1284
+ style: 'message',
1285
+ margin: [ 0, 0, 0, 12 ]
1286
+ } );
1269
1287
  }
1270
1288
 
1271
1289
  if ( config.title ) {
@@ -1280,9 +1298,9 @@ DataTable.ext.buttons.pdfHtml5 = {
1280
1298
  config.customize( doc, config );
1281
1299
  }
1282
1300
 
1283
- var pdf = pdfMake.createPdf( doc );
1301
+ var pdf = _pdfMake().createPdf( doc );
1284
1302
 
1285
- if ( config.download === 'open' && ! _isSafari() ) {
1303
+ if ( config.download === 'open' && ! _isDuffSafari() ) {
1286
1304
  pdf.open();
1287
1305
  }
1288
1306
  else {