effective_datatables 2.6.6 → 2.6.7

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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/dataTables/buttons/buttons.bootstrap.js +47 -47
  3. data/app/assets/javascripts/dataTables/buttons/buttons.colVis.js +182 -181
  4. data/app/assets/javascripts/dataTables/buttons/buttons.html5.js +1201 -684
  5. data/app/assets/javascripts/dataTables/buttons/buttons.print.js +144 -127
  6. data/app/assets/javascripts/dataTables/buttons/dataTables.buttons.js +1463 -1405
  7. data/app/assets/javascripts/dataTables/colreorder/dataTables.colReorder.js +27 -0
  8. data/app/assets/javascripts/dataTables/dataTables.bootstrap.js +182 -0
  9. data/app/assets/javascripts/dataTables/jquery.dataTables.js +15278 -0
  10. data/app/assets/javascripts/dataTables/jszip/jszip.js +9155 -0
  11. data/app/assets/javascripts/dataTables/responsive/dataTables.responsive.js +1232 -0
  12. data/app/assets/javascripts/dataTables/responsive/responsive.bootstrap.js +81 -0
  13. data/app/assets/javascripts/effective_datatables.js +7 -8
  14. data/app/assets/stylesheets/dataTables/buttons/{buttons.bootstrap.min.css → buttons.bootstrap.css} +0 -0
  15. data/app/assets/stylesheets/dataTables/colReorder/colReorder.bootstrap.css +11 -0
  16. data/app/assets/stylesheets/dataTables/{dataTables.bootstrap.min.css → dataTables.bootstrap.css} +1 -3
  17. data/app/assets/stylesheets/dataTables/responsive/responsive.bootstrap.css +181 -0
  18. data/app/assets/stylesheets/effective_datatables.scss +4 -10
  19. data/app/assets/stylesheets/effective_datatables/_overrides.scss.erb +5 -25
  20. data/lib/effective_datatables/version.rb +1 -1
  21. metadata +12 -16
  22. data/app/assets/javascripts/dataTables/dataTables.colReorder.min.js +0 -26
  23. data/app/assets/javascripts/dataTables/jquery.dataTables.bootstrap.js +0 -220
  24. data/app/assets/javascripts/dataTables/jquery.dataTables.min.js +0 -164
  25. data/app/assets/javascripts/dataTables/responsive/dataTables.responsive.min.js +0 -23
  26. data/app/assets/javascripts/dataTables/responsive/responsive.bootstrap.min.js +0 -7
  27. data/app/assets/javascripts/vendor/jszip.min.js +0 -14
  28. data/app/assets/stylesheets/dataTables/buttons/buttons.dataTables.min.css +0 -298
  29. data/app/assets/stylesheets/dataTables/colReorder/colReorder.bootstrap.min.css +0 -1
  30. data/app/assets/stylesheets/dataTables/colReorder/colReorder.dataTables.min.css +0 -1
  31. data/app/assets/stylesheets/dataTables/jquery.dataTables.min.css +0 -453
  32. data/app/assets/stylesheets/dataTables/responsive/responsive.bootstrap.min.css +0 -1
  33. data/app/assets/stylesheets/dataTables/responsive/responsive.dataTables.min.css +0 -1
@@ -1,44 +1,53 @@
1
1
  /*!
2
2
  * HTML5 export buttons for Buttons and DataTables.
3
- * 2015 SpryMedia Ltd - datatables.net/license
3
+ * 2016 SpryMedia Ltd - datatables.net/license
4
4
  *
5
- * FileSaver.js (2015-05-07.2) - MIT license
6
- * Copyright © 2015 Eli Grey - http://eligrey.com
5
+ * FileSaver.js (1.1.20160328) - MIT license
6
+ * Copyright © 2016 Eli Grey - http://eligrey.com
7
7
  */
8
8
 
9
9
  (function( factory ){
10
- if ( typeof define === 'function' && define.amd ) {
11
- // AMD
12
- define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
13
- return factory( $, window, document );
14
- } );
15
- }
16
- else if ( typeof exports === 'object' ) {
17
- // CommonJS
18
- module.exports = function (root, $) {
19
- if ( ! root ) {
20
- root = window;
21
- }
22
-
23
- if ( ! $ || ! $.fn.dataTable ) {
24
- $ = require('datatables.net')(root, $).$;
25
- }
26
-
27
- if ( ! $.fn.dataTable.Buttons ) {
28
- require('datatables.net-buttons')(root, $);
29
- }
30
-
31
- return factory( $, root, root.document );
32
- };
33
- }
34
- else {
35
- // Browser
36
- factory( jQuery, window, document );
37
- }
38
- }(function( $, window, document, undefined ) {
10
+ if ( typeof define === 'function' && define.amd ) {
11
+ // AMD
12
+ define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
13
+ return factory( $, window, document );
14
+ } );
15
+ }
16
+ else if ( typeof exports === 'object' ) {
17
+ // CommonJS
18
+ module.exports = function (root, $, jszip, pdfmake) {
19
+ if ( ! root ) {
20
+ root = window;
21
+ }
22
+
23
+ if ( ! $ || ! $.fn.dataTable ) {
24
+ $ = require('datatables.net')(root, $).$;
25
+ }
26
+
27
+ if ( ! $.fn.dataTable.Buttons ) {
28
+ require('datatables.net-buttons')(root, $);
29
+ }
30
+
31
+ return factory( $, root, root.document, jszip, pdfmake );
32
+ };
33
+ }
34
+ else {
35
+ // Browser
36
+ factory( jQuery, window, document );
37
+ }
38
+ }(function( $, window, document, jszip, pdfmake, undefined ) {
39
39
  'use strict';
40
40
  var DataTable = $.fn.dataTable;
41
41
 
42
+ // Allow the constructor to pass in JSZip and PDFMake from external requires.
43
+ // Otherwise, use globally defined variables, if they are available.
44
+ function _jsZip () {
45
+ return jszip || window.JSZip;
46
+ }
47
+ function _pdfMake () {
48
+ return pdfmake || window.pdfMake;
49
+ }
50
+
42
51
 
43
52
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
44
53
  * FileSaver.js dependency
@@ -47,229 +56,265 @@ var DataTable = $.fn.dataTable;
47
56
  /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */
48
57
 
49
58
  var _saveAs = (function(view) {
50
- // IE <10 is explicitly unsupported
51
- if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
52
- return;
53
- }
54
- var
55
- doc = view.document
56
- // only get URL when necessary in case Blob.js hasn't overridden it yet
57
- , get_URL = function() {
58
- return view.URL || view.webkitURL || view;
59
- }
60
- , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
61
- , can_use_save_link = "download" in save_link
62
- , click = function(node) {
63
- var event = doc.createEvent("MouseEvents");
64
- event.initMouseEvent(
65
- "click", true, false, view, 0, 0, 0, 0, 0
66
- , false, false, false, false, 0, null
67
- );
68
- node.dispatchEvent(event);
69
- }
70
- , webkit_req_fs = view.webkitRequestFileSystem
71
- , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
72
- , throw_outside = function(ex) {
73
- (view.setImmediate || view.setTimeout)(function() {
74
- throw ex;
75
- }, 0);
76
- }
77
- , force_saveable_type = "application/octet-stream"
78
- , fs_min_size = 0
79
- // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
80
- // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
81
- // for the reasoning behind the timeout and revocation flow
82
- , arbitrary_revoke_timeout = 500 // in ms
83
- , revoke = function(file) {
84
- var revoker = function() {
85
- if (typeof file === "string") { // file is an object URL
86
- get_URL().revokeObjectURL(file);
87
- } else { // file is a File
88
- file.remove();
89
- }
90
- };
91
- if (view.chrome) {
92
- revoker();
93
- } else {
94
- setTimeout(revoker, arbitrary_revoke_timeout);
95
- }
96
- }
97
- , dispatch = function(filesaver, event_types, event) {
98
- event_types = [].concat(event_types);
99
- var i = event_types.length;
100
- while (i--) {
101
- var listener = filesaver["on" + event_types[i]];
102
- if (typeof listener === "function") {
103
- try {
104
- listener.call(filesaver, event || filesaver);
105
- } catch (ex) {
106
- throw_outside(ex);
107
- }
108
- }
109
- }
110
- }
111
- , auto_bom = function(blob) {
112
- // prepend BOM for UTF-8 XML and text/* types (including HTML)
113
- if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
114
- return new Blob(["\ufeff", blob], {type: blob.type});
115
- }
116
- return blob;
117
- }
118
- , FileSaver = function(blob, name) {
119
- blob = auto_bom(blob);
120
- // First try a.download, then web filesystem, then object URLs
121
- var
122
- filesaver = this
123
- , type = blob.type
124
- , blob_changed = false
125
- , object_url
126
- , target_view
127
- , dispatch_all = function() {
128
- dispatch(filesaver, "writestart progress write writeend".split(" "));
129
- }
130
- // on any filesys errors revert to saving with object URLs
131
- , fs_error = function() {
132
- // don't create more object URLs than needed
133
- if (blob_changed || !object_url) {
134
- object_url = get_URL().createObjectURL(blob);
135
- }
136
- if (target_view) {
137
- target_view.location.href = object_url;
138
- } else {
139
- var new_tab = view.open(object_url, "_blank");
140
- if (new_tab === undefined && typeof safari !== "undefined") {
141
- //Apple do not allow window.open, see http://bit.ly/1kZffRI
142
- view.location.href = object_url;
143
- }
144
- }
145
- filesaver.readyState = filesaver.DONE;
146
- dispatch_all();
147
- revoke(object_url);
148
- }
149
- , abortable = function(func) {
150
- return function() {
151
- if (filesaver.readyState !== filesaver.DONE) {
152
- return func.apply(this, arguments);
153
- }
154
- };
155
- }
156
- , create_if_not_found = {create: true, exclusive: false}
157
- , slice
158
- ;
159
- filesaver.readyState = filesaver.INIT;
160
- if (!name) {
161
- name = "download";
162
- }
163
- if (can_use_save_link) {
164
- object_url = get_URL().createObjectURL(blob);
165
- save_link.href = object_url;
166
- save_link.download = name;
167
- click(save_link);
168
- filesaver.readyState = filesaver.DONE;
169
- dispatch_all();
170
- revoke(object_url);
171
- return;
172
- }
173
- // Object and web filesystem URLs have a problem saving in Google Chrome when
174
- // viewed in a tab, so I force save with application/octet-stream
175
- // http://code.google.com/p/chromium/issues/detail?id=91158
176
- // Update: Google errantly closed 91158, I submitted it again:
177
- // https://code.google.com/p/chromium/issues/detail?id=389642
178
- if (view.chrome && type && type !== force_saveable_type) {
179
- slice = blob.slice || blob.webkitSlice;
180
- blob = slice.call(blob, 0, blob.size, force_saveable_type);
181
- blob_changed = true;
182
- }
183
- // Since I can't be sure that the guessed media type will trigger a download
184
- // in WebKit, I append .download to the filename.
185
- // https://bugs.webkit.org/show_bug.cgi?id=65440
186
- if (webkit_req_fs && name !== "download") {
187
- name += ".download";
188
- }
189
- if (type === force_saveable_type || webkit_req_fs) {
190
- target_view = view;
191
- }
192
- if (!req_fs) {
193
- fs_error();
194
- return;
195
- }
196
- fs_min_size += blob.size;
197
- req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
198
- fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
199
- var save = function() {
200
- dir.getFile(name, create_if_not_found, abortable(function(file) {
201
- file.createWriter(abortable(function(writer) {
202
- writer.onwriteend = function(event) {
203
- target_view.location.href = file.toURL();
204
- filesaver.readyState = filesaver.DONE;
205
- dispatch(filesaver, "writeend", event);
206
- revoke(file);
207
- };
208
- writer.onerror = function() {
209
- var error = writer.error;
210
- if (error.code !== error.ABORT_ERR) {
211
- fs_error();
212
- }
213
- };
214
- "writestart progress write abort".split(" ").forEach(function(event) {
215
- writer["on" + event] = filesaver["on" + event];
216
- });
217
- writer.write(blob);
218
- filesaver.abort = function() {
219
- writer.abort();
220
- filesaver.readyState = filesaver.DONE;
221
- };
222
- filesaver.readyState = filesaver.WRITING;
223
- }), fs_error);
224
- }), fs_error);
225
- };
226
- dir.getFile(name, {create: false}, abortable(function(file) {
227
- // delete file if it already exists
228
- file.remove();
229
- save();
230
- }), abortable(function(ex) {
231
- if (ex.code === ex.NOT_FOUND_ERR) {
232
- save();
233
- } else {
234
- fs_error();
235
- }
236
- }));
237
- }), fs_error);
238
- }), fs_error);
239
- }
240
- , FS_proto = FileSaver.prototype
241
- , saveAs = function(blob, name) {
242
- return new FileSaver(blob, name);
243
- }
244
- ;
245
- // IE 10+ (native saveAs)
246
- if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
247
- return function(blob, name) {
248
- return navigator.msSaveOrOpenBlob(auto_bom(blob), name);
249
- };
250
- }
251
-
252
- FS_proto.abort = function() {
253
- var filesaver = this;
254
- filesaver.readyState = filesaver.DONE;
255
- dispatch(filesaver, "abort");
256
- };
257
- FS_proto.readyState = FS_proto.INIT = 0;
258
- FS_proto.WRITING = 1;
259
- FS_proto.DONE = 2;
260
-
261
- FS_proto.error =
262
- FS_proto.onwritestart =
263
- FS_proto.onprogress =
264
- FS_proto.onwrite =
265
- FS_proto.onabort =
266
- FS_proto.onerror =
267
- FS_proto.onwriteend =
268
- null;
269
-
270
- return saveAs;
271
- }(window));
272
-
59
+ "use strict";
60
+ // IE <10 is explicitly unsupported
61
+ if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) {
62
+ return;
63
+ }
64
+ var
65
+ doc = view.document
66
+ // only get URL when necessary in case Blob.js hasn't overridden it yet
67
+ , get_URL = function() {
68
+ return view.URL || view.webkitURL || view;
69
+ }
70
+ , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
71
+ , can_use_save_link = "download" in save_link
72
+ , click = function(node) {
73
+ var event = new MouseEvent("click");
74
+ node.dispatchEvent(event);
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
79
+ , throw_outside = function(ex) {
80
+ (view.setImmediate || view.setTimeout)(function() {
81
+ throw ex;
82
+ }, 0);
83
+ }
84
+ , force_saveable_type = "application/octet-stream"
85
+ , fs_min_size = 0
86
+ // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to
87
+ , arbitrary_revoke_timeout = 1000 * 40 // in ms
88
+ , revoke = function(file) {
89
+ var revoker = function() {
90
+ if (typeof file === "string") { // file is an object URL
91
+ get_URL().revokeObjectURL(file);
92
+ } else { // file is a File
93
+ file.remove();
94
+ }
95
+ };
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
+ setTimeout(revoker, arbitrary_revoke_timeout);
113
+ }
114
+ , dispatch = function(filesaver, event_types, event) {
115
+ event_types = [].concat(event_types);
116
+ var i = event_types.length;
117
+ while (i--) {
118
+ var listener = filesaver["on" + event_types[i]];
119
+ if (typeof listener === "function") {
120
+ try {
121
+ listener.call(filesaver, event || filesaver);
122
+ } catch (ex) {
123
+ throw_outside(ex);
124
+ }
125
+ }
126
+ }
127
+ }
128
+ , auto_bom = function(blob) {
129
+ // prepend BOM for UTF-8 XML and text/* types (including HTML)
130
+ 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});
132
+ }
133
+ return blob;
134
+ }
135
+ , FileSaver = function(blob, name, no_auto_bom) {
136
+ if (!no_auto_bom) {
137
+ blob = auto_bom(blob);
138
+ }
139
+ // First try a.download, then web filesystem, then object URLs
140
+ var
141
+ filesaver = this
142
+ , type = blob.type
143
+ , blob_changed = false
144
+ , object_url
145
+ , target_view
146
+ , dispatch_all = function() {
147
+ dispatch(filesaver, "writestart progress write writeend".split(" "));
148
+ }
149
+ // on any filesys errors revert to saving with object URLs
150
+ , fs_error = function() {
151
+ if (target_view && is_safari && typeof FileReader !== "undefined") {
152
+ // Safari doesn't allow downloading of blob urls
153
+ var reader = new FileReader();
154
+ reader.onloadend = function() {
155
+ var base64Data = reader.result;
156
+ target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/));
157
+ filesaver.readyState = filesaver.DONE;
158
+ dispatch_all();
159
+ };
160
+ reader.readAsDataURL(blob);
161
+ filesaver.readyState = filesaver.INIT;
162
+ return;
163
+ }
164
+ // don't create more object URLs than needed
165
+ if (blob_changed || !object_url) {
166
+ object_url = get_URL().createObjectURL(blob);
167
+ }
168
+ if (target_view) {
169
+ target_view.location.href = object_url;
170
+ } 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
175
+ }
176
+ }
177
+ filesaver.readyState = filesaver.DONE;
178
+ dispatch_all();
179
+ revoke(object_url);
180
+ }
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
+ ;
191
+ filesaver.readyState = filesaver.INIT;
192
+ if (!name) {
193
+ name = "download";
194
+ }
195
+ if (can_use_save_link) {
196
+ object_url = get_URL().createObjectURL(blob);
197
+ setTimeout(function() {
198
+ save_link.href = object_url;
199
+ save_link.download = name;
200
+ click(save_link);
201
+ dispatch_all();
202
+ revoke(object_url);
203
+ filesaver.readyState = filesaver.DONE;
204
+ });
205
+ return;
206
+ }
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);
273
+ }
274
+ , FS_proto = FileSaver.prototype
275
+ , saveAs = function(blob, name, no_auto_bom) {
276
+ return new FileSaver(blob, name, no_auto_bom);
277
+ }
278
+ ;
279
+ // IE 10+ (native saveAs)
280
+ if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) {
281
+ return function(blob, name, no_auto_bom) {
282
+ if (!no_auto_bom) {
283
+ blob = auto_bom(blob);
284
+ }
285
+ return navigator.msSaveOrOpenBlob(blob, name || "download");
286
+ };
287
+ }
288
+
289
+ FS_proto.abort = function() {
290
+ var filesaver = this;
291
+ filesaver.readyState = filesaver.DONE;
292
+ dispatch(filesaver, "abort");
293
+ };
294
+ FS_proto.readyState = FS_proto.INIT = 0;
295
+ FS_proto.WRITING = 1;
296
+ FS_proto.DONE = 2;
297
+
298
+ FS_proto.error =
299
+ FS_proto.onwritestart =
300
+ FS_proto.onprogress =
301
+ FS_proto.onwrite =
302
+ FS_proto.onabort =
303
+ FS_proto.onerror =
304
+ FS_proto.onwriteend =
305
+ null;
306
+
307
+ return saveAs;
308
+ }(
309
+ typeof self !== "undefined" && self
310
+ || typeof window !== "undefined" && window
311
+ || this.content
312
+ ));
313
+
314
+
315
+ // Expose file saver on the DataTables API. Can't attach to `DataTables.Buttons`
316
+ // since this file can be loaded before Button's core!
317
+ DataTable.fileSave = _saveAs;
273
318
 
274
319
 
275
320
  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@@ -279,105 +324,129 @@ var _saveAs = (function(view) {
279
324
  /**
280
325
  * Get the file name for an exported file.
281
326
  *
282
- * @param {object} config Button configuration
327
+ * @param {object} config Button configuration
283
328
  * @param {boolean} incExtension Include the file name extension
284
329
  */
285
330
  var _filename = function ( config, incExtension )
286
331
  {
287
- // Backwards compatibility
288
- var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined ?
289
- config.title :
290
- config.filename;
332
+ // Backwards compatibility
333
+ var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined ?
334
+ config.title :
335
+ config.filename;
336
+
337
+ if ( typeof filename === 'function' ) {
338
+ filename = filename();
339
+ }
340
+
341
+ if ( filename.indexOf( '*' ) !== -1 ) {
342
+ filename = $.trim( filename.replace( '*', $('title').text() ) );
343
+ }
344
+
345
+ // Strip characters which the OS will object to
346
+ filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
347
+
348
+ return incExtension === undefined || incExtension === true ?
349
+ filename+config.extension :
350
+ filename;
351
+ };
291
352
 
292
- if ( filename.indexOf( '*' ) !== -1 ) {
293
- filename = filename.replace( '*', $('title').text() );
294
- }
353
+ /**
354
+ * Get the sheet name for Excel exports.
355
+ *
356
+ * @param {object} config Button configuration
357
+ */
358
+ var _sheetname = function ( config )
359
+ {
360
+ var sheetName = 'Sheet1';
295
361
 
296
- // Strip characters which the OS will object to
297
- filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
362
+ if ( config.sheetName ) {
363
+ sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
364
+ }
298
365
 
299
- return incExtension === undefined || incExtension === true ?
300
- filename+config.extension :
301
- filename;
366
+ return sheetName;
302
367
  };
303
368
 
304
369
  /**
305
370
  * Get the title for an exported file.
306
371
  *
307
- * @param {object} config Button configuration
372
+ * @param {object} config Button configuration
308
373
  */
309
374
  var _title = function ( config )
310
375
  {
311
- var title = config.title;
376
+ var title = config.title;
377
+
378
+ if ( typeof title === 'function' ) {
379
+ title = title();
380
+ }
312
381
 
313
- return title.indexOf( '*' ) !== -1 ?
314
- title.replace( '*', $('title').text() ) :
315
- title;
382
+ return title.indexOf( '*' ) !== -1 ?
383
+ title.replace( '*', $('title').text() || 'Exported data' ) :
384
+ title;
316
385
  };
317
386
 
318
387
  /**
319
388
  * Get the newline character(s)
320
389
  *
321
- * @param {object} config Button configuration
322
- * @return {string} Newline character
390
+ * @param {object} config Button configuration
391
+ * @return {string} Newline character
323
392
  */
324
393
  var _newLine = function ( config )
325
394
  {
326
- return config.newline ?
327
- config.newline :
328
- navigator.userAgent.match(/Windows/) ?
329
- '\r\n' :
330
- '\n';
395
+ return config.newline ?
396
+ config.newline :
397
+ navigator.userAgent.match(/Windows/) ?
398
+ '\r\n' :
399
+ '\n';
331
400
  };
332
401
 
333
402
  /**
334
403
  * Combine the data from the `buttons.exportData` method into a string that
335
404
  * will be used in the export file.
336
405
  *
337
- * @param {DataTable.Api} dt DataTables API instance
338
- * @param {object} config Button configuration
339
- * @return {object} The data to export
406
+ * @param {DataTable.Api} dt DataTables API instance
407
+ * @param {object} config Button configuration
408
+ * @return {object} The data to export
340
409
  */
341
410
  var _exportData = function ( dt, config )
342
411
  {
343
- var newLine = _newLine( config );
344
- var data = dt.buttons.exportData( config.exportOptions );
345
- var boundary = config.fieldBoundary;
346
- var separator = config.fieldSeparator;
347
- var reBoundary = new RegExp( boundary, 'g' );
348
- var escapeChar = config.escapeChar !== undefined ?
349
- config.escapeChar :
350
- '\\';
351
- var join = function ( a ) {
352
- var s = '';
353
-
354
- // If there is a field boundary, then we might need to escape it in
355
- // the source data
356
- for ( var i=0, ien=a.length ; i<ien ; i++ ) {
357
- if ( i > 0 ) {
358
- s += separator;
359
- }
360
-
361
- s += boundary ?
362
- boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :
363
- a[i];
364
- }
365
-
366
- return s;
367
- };
368
-
369
- var header = config.header ? join( data.header )+newLine : '';
370
- var footer = config.footer ? newLine+join( data.footer ) : '';
371
- var body = [];
372
-
373
- for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
374
- body.push( join( data.body[i] ) );
375
- }
376
-
377
- return {
378
- str: header + body.join( newLine ) + footer,
379
- rows: body.length
380
- };
412
+ var newLine = _newLine( config );
413
+ var data = dt.buttons.exportData( config.exportOptions );
414
+ var boundary = config.fieldBoundary;
415
+ var separator = config.fieldSeparator;
416
+ var reBoundary = new RegExp( boundary, 'g' );
417
+ var escapeChar = config.escapeChar !== undefined ?
418
+ config.escapeChar :
419
+ '\\';
420
+ var join = function ( a ) {
421
+ var s = '';
422
+
423
+ // If there is a field boundary, then we might need to escape it in
424
+ // the source data
425
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
426
+ if ( i > 0 ) {
427
+ s += separator;
428
+ }
429
+
430
+ s += boundary ?
431
+ boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :
432
+ a[i];
433
+ }
434
+
435
+ return s;
436
+ };
437
+
438
+ var header = config.header ? join( data.header )+newLine : '';
439
+ var footer = config.footer && data.footer ? newLine+join( data.footer ) : '';
440
+ var body = [];
441
+
442
+ for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
443
+ body.push( join( data.body[i] ) );
444
+ }
445
+
446
+ return {
447
+ str: header + body.join( newLine ) + footer,
448
+ rows: body.length
449
+ };
381
450
  };
382
451
 
383
452
  /**
@@ -389,52 +458,386 @@ var _exportData = function ( dt, config )
389
458
  */
390
459
  var _isSafari = function ()
391
460
  {
392
- return navigator.userAgent.indexOf('Safari') !== -1 &&
393
- navigator.userAgent.indexOf('Chrome') === -1 &&
394
- navigator.userAgent.indexOf('Opera') === -1;
461
+ return navigator.userAgent.indexOf('Safari') !== -1 &&
462
+ navigator.userAgent.indexOf('Chrome') === -1 &&
463
+ navigator.userAgent.indexOf('Opera') === -1;
395
464
  };
396
465
 
466
+ /**
467
+ * Convert from numeric position to letter for column names in Excel
468
+ * @param {int} n Column number
469
+ * @return {string} Column letter(s) name
470
+ */
471
+ function createCellPos( n ){
472
+ var ordA = 'A'.charCodeAt(0);
473
+ var ordZ = 'Z'.charCodeAt(0);
474
+ var len = ordZ - ordA + 1;
475
+ var s = "";
476
+
477
+ while( n >= 0 ) {
478
+ s = String.fromCharCode(n % len + ordA) + s;
479
+ n = Math.floor(n / len) - 1;
480
+ }
481
+
482
+ return s;
483
+ }
484
+
485
+ try {
486
+ var _serialiser = new XMLSerializer();
487
+ var _ieExcel;
488
+ }
489
+ catch (t) {}
490
+
491
+ /**
492
+ * Recursively add XML files from an object's structure to a ZIP file. This
493
+ * allows the XSLX file to be easily defined with an object's structure matching
494
+ * the files structure.
495
+ *
496
+ * @param {JSZip} zip ZIP package
497
+ * @param {object} obj Object to add (recursive)
498
+ */
499
+ function _addToZip( zip, obj ) {
500
+ if ( _ieExcel === undefined ) {
501
+ // Detect if we are dealing with IE's _awful_ serialiser by seeing if it
502
+ // drop attributes
503
+ _ieExcel = _serialiser
504
+ .serializeToString(
505
+ $.parseXML( excelStrings['xl/worksheets/sheet1.xml'] )
506
+ )
507
+ .indexOf( 'xmlns:r' ) === -1;
508
+ }
509
+
510
+ $.each( obj, function ( name, val ) {
511
+ if ( $.isPlainObject( val ) ) {
512
+ var newDir = zip.folder( name );
513
+ _addToZip( newDir, val );
514
+ }
515
+ else {
516
+ if ( _ieExcel ) {
517
+ // IE's XML serialiser will drop some name space attributes from
518
+ // from the root node, so we need to save them. Do this by
519
+ // replacing the namespace nodes with a regular attribute that
520
+ // we convert back when serialised. Edge does not have this
521
+ // issue
522
+ var worksheet = val.childNodes[0];
523
+ var i, ien;
524
+ var attrs = [];
525
+
526
+ for ( i=worksheet.attributes.length-1 ; i>=0 ; i-- ) {
527
+ var attrName = worksheet.attributes[i].nodeName;
528
+ var attrValue = worksheet.attributes[i].nodeValue;
529
+
530
+ if ( attrName.indexOf( ':' ) !== -1 ) {
531
+ attrs.push( { name: attrName, value: attrValue } );
532
+
533
+ worksheet.removeAttribute( attrName );
534
+ }
535
+ }
536
+
537
+ for ( i=0, ien=attrs.length ; i<ien ; i++ ) {
538
+ var attr = val.createAttribute( attrs[i].name.replace( ':', '_dt_b_namespace_token_' ) );
539
+ attr.value = attrs[i].value;
540
+ worksheet.setAttributeNode( attr );
541
+ }
542
+ }
543
+
544
+ var str = _serialiser.serializeToString(val);
545
+
546
+ // Fix IE's XML
547
+ if ( _ieExcel ) {
548
+ // IE doesn't include the XML declaration
549
+ if ( str.indexOf( '<?xml' ) === -1 ) {
550
+ str = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+str;
551
+ }
552
+
553
+ // Return namespace attributes to being as such
554
+ str = str.replace( /_dt_b_namespace_token_/g, ':' );
555
+ }
556
+
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>' );
562
+
563
+ zip.file( name, str );
564
+ }
565
+ } );
566
+ }
567
+
568
+ /**
569
+ * Create an XML node and add any children, attributes, etc without needing to
570
+ * be verbose in the DOM.
571
+ *
572
+ * @param {object} doc XML document
573
+ * @param {string} nodeName Node name
574
+ * @param {object} opts Options - can be `attr` (attributes), `children`
575
+ * (child nodes) and `text` (text content)
576
+ * @return {node} Created node
577
+ */
578
+ function _createNode( doc, nodeName, opts ) {
579
+ var tempNode = doc.createElement( nodeName );
580
+
581
+ if ( opts ) {
582
+ if ( opts.attr ) {
583
+ $(tempNode).attr( opts.attr );
584
+ }
585
+
586
+ if( opts.children ) {
587
+ $.each( opts.children, function ( key, value ) {
588
+ tempNode.appendChild( value );
589
+ });
590
+ }
397
591
 
398
- // Excel - Pre-defined strings to build a minimal XLSX file
592
+ if( opts.text ) {
593
+ tempNode.appendChild( doc.createTextNode( opts.text ) );
594
+ }
595
+ }
596
+
597
+ return tempNode;
598
+ }
599
+
600
+ /**
601
+ * Get the width for an Excel column based on the contents of that column
602
+ * @param {object} data Data for export
603
+ * @param {int} col Column index
604
+ * @return {int} Column width
605
+ */
606
+ function _excelColWidth( data, col ) {
607
+ var max = data.header[col].length;
608
+ var len;
609
+
610
+ if ( data.footer && data.footer[col].length > max ) {
611
+ max = data.footer[col].length;
612
+ }
613
+
614
+ for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
615
+ len = data.body[i][col].toString().length;
616
+
617
+ if ( len > max ) {
618
+ max = len;
619
+ }
620
+
621
+ // Max width rather than having potentially massive column widths
622
+ if ( max > 40 ) {
623
+ break;
624
+ }
625
+ }
626
+
627
+ // And a min width
628
+ return max > 5 ? max : 5;
629
+ }
630
+
631
+ // Excel - Pre-defined strings to build a basic XLSX file
399
632
  var excelStrings = {
400
- "_rels/.rels": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
401
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\
402
- <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>\
403
- </Relationships>',
404
-
405
- "xl/_rels/workbook.xml.rels": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
406
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">\
407
- <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>\
408
- </Relationships>',
409
-
410
- "[Content_Types].xml": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
411
- <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">\
412
- <Default Extension="xml" ContentType="application/xml"/>\
413
- <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>\
414
- <Default Extension="jpeg" ContentType="image/jpeg"/>\
415
- <Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>\
416
- <Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>\
417
- </Types>',
418
-
419
- "xl/workbook.xml": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
420
- <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">\
421
- <fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>\
422
- <workbookPr showInkAnnotation="0" autoCompressPictures="0"/>\
423
- <bookViews>\
424
- <workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>\
425
- </bookViews>\
426
- <sheets>\
427
- <sheet name="Sheet1" sheetId="1" r:id="rId1"/>\
428
- </sheets>\
429
- </workbook>',
430
-
431
- "xl/worksheets/sheet1.xml": '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\
432
- <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">\
433
- <sheetData>\
434
- __DATA__\
435
- </sheetData>\
436
- </worksheet>'
633
+ "_rels/.rels":
634
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
635
+ '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
636
+ '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>'+
637
+ '</Relationships>',
638
+
639
+ "xl/_rels/workbook.xml.rels":
640
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
641
+ '<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">'+
642
+ '<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>'+
643
+ '<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>'+
644
+ '</Relationships>',
645
+
646
+ "[Content_Types].xml":
647
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
648
+ '<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">'+
649
+ '<Default Extension="xml" ContentType="application/xml" />'+
650
+ '<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />'+
651
+ '<Default Extension="jpeg" ContentType="image/jpeg" />'+
652
+ '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />'+
653
+ '<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />'+
654
+ '<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />'+
655
+ '</Types>',
656
+
657
+ "xl/workbook.xml":
658
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
659
+ '<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">'+
660
+ '<fileVersion appName="xl" lastEdited="5" lowestEdited="5" rupBuild="24816"/>'+
661
+ '<workbookPr showInkAnnotation="0" autoCompressPictures="0"/>'+
662
+ '<bookViews>'+
663
+ '<workbookView xWindow="0" yWindow="0" windowWidth="25600" windowHeight="19020" tabRatio="500"/>'+
664
+ '</bookViews>'+
665
+ '<sheets>'+
666
+ '<sheet name="" sheetId="1" r:id="rId1"/>'+
667
+ '</sheets>'+
668
+ '</workbook>',
669
+
670
+ "xl/worksheets/sheet1.xml":
671
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
672
+ '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">'+
673
+ '<sheetData/>'+
674
+ '</worksheet>',
675
+
676
+ "xl/styles.xml":
677
+ '<?xml version="1.0" encoding="UTF-8"?>'+
678
+ '<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">'+
679
+ '<fonts count="5" x14ac:knownFonts="1">'+
680
+ '<font>'+
681
+ '<sz val="11" />'+
682
+ '<name val="Calibri" />'+
683
+ '</font>'+
684
+ '<font>'+
685
+ '<sz val="11" />'+
686
+ '<name val="Calibri" />'+
687
+ '<color rgb="FFFFFFFF" />'+
688
+ '</font>'+
689
+ '<font>'+
690
+ '<sz val="11" />'+
691
+ '<name val="Calibri" />'+
692
+ '<b />'+
693
+ '</font>'+
694
+ '<font>'+
695
+ '<sz val="11" />'+
696
+ '<name val="Calibri" />'+
697
+ '<i />'+
698
+ '</font>'+
699
+ '<font>'+
700
+ '<sz val="11" />'+
701
+ '<name val="Calibri" />'+
702
+ '<u />'+
703
+ '</font>'+
704
+ '</fonts>'+
705
+ '<fills count="6">'+
706
+ '<fill>'+
707
+ '<patternFill patternType="none" />'+
708
+ '</fill>'+
709
+ '<fill/>'+ // Excel appears to use this as a dotted background regardless of values
710
+ '<fill>'+
711
+ '<patternFill patternType="solid">'+
712
+ '<fgColor rgb="FFD9D9D9" />'+
713
+ '<bgColor indexed="64" />'+
714
+ '</patternFill>'+
715
+ '</fill>'+
716
+ '<fill>'+
717
+ '<patternFill patternType="solid">'+
718
+ '<fgColor rgb="FFD99795" />'+
719
+ '<bgColor indexed="64" />'+
720
+ '</patternFill>'+
721
+ '</fill>'+
722
+ '<fill>'+
723
+ '<patternFill patternType="solid">'+
724
+ '<fgColor rgb="ffc6efce" />'+
725
+ '<bgColor indexed="64" />'+
726
+ '</patternFill>'+
727
+ '</fill>'+
728
+ '<fill>'+
729
+ '<patternFill patternType="solid">'+
730
+ '<fgColor rgb="ffc6cfef" />'+
731
+ '<bgColor indexed="64" />'+
732
+ '</patternFill>'+
733
+ '</fill>'+
734
+ '</fills>'+
735
+ '<borders count="2">'+
736
+ '<border>'+
737
+ '<left />'+
738
+ '<right />'+
739
+ '<top />'+
740
+ '<bottom />'+
741
+ '<diagonal />'+
742
+ '</border>'+
743
+ '<border diagonalUp="false" diagonalDown="false">'+
744
+ '<left style="thin">'+
745
+ '<color auto="1" />'+
746
+ '</left>'+
747
+ '<right style="thin">'+
748
+ '<color auto="1" />'+
749
+ '</right>'+
750
+ '<top style="thin">'+
751
+ '<color auto="1" />'+
752
+ '</top>'+
753
+ '<bottom style="thin">'+
754
+ '<color auto="1" />'+
755
+ '</bottom>'+
756
+ '<diagonal />'+
757
+ '</border>'+
758
+ '</borders>'+
759
+ '<cellStyleXfs count="1">'+
760
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" />'+
761
+ '</cellStyleXfs>'+
762
+ '<cellXfs count="56">'+
763
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
764
+ '<xf numFmtId="0" fontId="1" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
765
+ '<xf numFmtId="0" fontId="2" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
766
+ '<xf numFmtId="0" fontId="3" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
767
+ '<xf numFmtId="0" fontId="4" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
768
+ '<xf numFmtId="0" fontId="0" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
769
+ '<xf numFmtId="0" fontId="1" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
770
+ '<xf numFmtId="0" fontId="2" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
771
+ '<xf numFmtId="0" fontId="3" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
772
+ '<xf numFmtId="0" fontId="4" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
773
+ '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
774
+ '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
775
+ '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
776
+ '<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
777
+ '<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
778
+ '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
779
+ '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
780
+ '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
781
+ '<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
782
+ '<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
783
+ '<xf numFmtId="0" fontId="0" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
784
+ '<xf numFmtId="0" fontId="1" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
785
+ '<xf numFmtId="0" fontId="2" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
786
+ '<xf numFmtId="0" fontId="3" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
787
+ '<xf numFmtId="0" fontId="4" fillId="5" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
788
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
789
+ '<xf numFmtId="0" fontId="1" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
790
+ '<xf numFmtId="0" fontId="2" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
791
+ '<xf numFmtId="0" fontId="3" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
792
+ '<xf numFmtId="0" fontId="4" fillId="0" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
793
+ '<xf numFmtId="0" fontId="0" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
794
+ '<xf numFmtId="0" fontId="1" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
795
+ '<xf numFmtId="0" fontId="2" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
796
+ '<xf numFmtId="0" fontId="3" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
797
+ '<xf numFmtId="0" fontId="4" fillId="2" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
798
+ '<xf numFmtId="0" fontId="0" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
799
+ '<xf numFmtId="0" fontId="1" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
800
+ '<xf numFmtId="0" fontId="2" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
801
+ '<xf numFmtId="0" fontId="3" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
802
+ '<xf numFmtId="0" fontId="4" fillId="3" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
803
+ '<xf numFmtId="0" fontId="0" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
804
+ '<xf numFmtId="0" fontId="1" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
805
+ '<xf numFmtId="0" fontId="2" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
806
+ '<xf numFmtId="0" fontId="3" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
807
+ '<xf numFmtId="0" fontId="4" fillId="4" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
808
+ '<xf numFmtId="0" fontId="0" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
809
+ '<xf numFmtId="0" fontId="1" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
810
+ '<xf numFmtId="0" fontId="2" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
811
+ '<xf numFmtId="0" fontId="3" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
812
+ '<xf numFmtId="0" fontId="4" fillId="5" borderId="1" applyFont="1" applyFill="1" applyBorder="1"/>'+
813
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
814
+ '<alignment horizontal="left"/>'+
815
+ '</xf>'+
816
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
817
+ '<alignment horizontal="center"/>'+
818
+ '</xf>'+
819
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
820
+ '<alignment horizontal="right"/>'+
821
+ '</xf>'+
822
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
823
+ '<alignment horizontal="fill"/>'+
824
+ '</xf>'+
825
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
826
+ '<alignment textRotation="90"/>'+
827
+ '</xf>'+
828
+ '<xf numFmtId="0" fontId="0" fillId="0" borderId="0" applyFont="1" applyFill="1" applyBorder="1" xfId="0" applyAlignment="1">'+
829
+ '<alignment wrapText="1"/>'+
830
+ '</xf>'+
831
+ '</cellXfs>'+
832
+ '<cellStyles count="1">'+
833
+ '<cellStyle name="Normal" xfId="0" builtinId="0" />'+
834
+ '</cellStyles>'+
835
+ '<dxfs count="0" />'+
836
+ '<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4" />'+
837
+ '</styleSheet>'
437
838
  };
839
+ // Note we could use 3 `for` loops for the styles, but when gzipped there is
840
+ // virtually no difference in size, since the above can be easily compressed
438
841
 
439
842
 
440
843
 
@@ -446,381 +849,495 @@ var excelStrings = {
446
849
  // Copy to clipboard
447
850
  //
448
851
  DataTable.ext.buttons.copyHtml5 = {
449
- className: 'buttons-copy buttons-html5',
450
-
451
- text: function ( dt ) {
452
- return dt.i18n( 'buttons.copy', 'Copy' );
453
- },
454
-
455
- action: function ( e, dt, button, config ) {
456
- var exportData = _exportData( dt, config );
457
- var output = exportData.str;
458
- var hiddenDiv = $('<div/>')
459
- .css( {
460
- height: 1,
461
- width: 1,
462
- overflow: 'hidden',
463
- position: 'fixed',
464
- top: 0,
465
- left: 0
466
- } );
467
- var textarea = $('<textarea readonly/>')
468
- .val( output )
469
- .appendTo( hiddenDiv );
470
-
471
- // For browsers that support the copy execCommand, try to use it
472
- if ( document.queryCommandSupported('copy') ) {
473
- hiddenDiv.appendTo( 'body' );
474
- textarea[0].focus();
475
- textarea[0].select();
476
-
477
- try {
478
- document.execCommand( 'copy' );
479
- hiddenDiv.remove();
480
-
481
- dt.buttons.info(
482
- dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
483
- dt.i18n( 'buttons.copySuccess', {
484
- 1: "Copied one row to clipboard",
485
- _: "Copied %d rows to clipboard"
486
- }, exportData.rows ),
487
- 2000
488
- );
489
-
490
- return;
491
- }
492
- catch (t) {}
493
- }
494
-
495
- // Otherwise we show the text box and instruct the user to use it
496
- var message = $('<span>'+dt.i18n( 'buttons.copyKeys',
497
- 'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+
498
- 'To cancel, click this message or press escape.' )+'</span>'
499
- )
500
- .append( hiddenDiv );
501
-
502
- dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );
503
-
504
- // Select the text so when the user activates their system clipboard
505
- // it will copy that text
506
- textarea[0].focus();
507
- textarea[0].select();
508
-
509
- // Event to hide the message when the user is done
510
- var container = $(message).closest('.dt-button-info');
511
- var close = function () {
512
- container.off( 'click.buttons-copy' );
513
- $(document).off( '.buttons-copy' );
514
- dt.buttons.info( false );
515
- };
516
-
517
- container.on( 'click.buttons-copy', close );
518
- $(document)
519
- .on( 'keydown.buttons-copy', function (e) {
520
- if ( e.keyCode === 27 ) { // esc
521
- close();
522
- }
523
- } )
524
- .on( 'copy.buttons-copy cut.buttons-copy', function () {
525
- close();
526
- } );
527
- },
528
-
529
- exportOptions: {},
530
-
531
- fieldSeparator: '\t',
532
-
533
- fieldBoundary: '',
534
-
535
- header: true,
536
-
537
- footer: false
852
+ className: 'buttons-copy buttons-html5',
853
+
854
+ text: function ( dt ) {
855
+ return dt.i18n( 'buttons.copy', 'Copy' );
856
+ },
857
+
858
+ action: function ( e, dt, button, config ) {
859
+ var exportData = _exportData( dt, config );
860
+ var output = exportData.str;
861
+ var hiddenDiv = $('<div/>')
862
+ .css( {
863
+ height: 1,
864
+ width: 1,
865
+ overflow: 'hidden',
866
+ position: 'fixed',
867
+ top: 0,
868
+ left: 0
869
+ } );
870
+
871
+ if ( config.customize ) {
872
+ output = config.customize( output, config );
873
+ }
874
+
875
+ var textarea = $('<textarea readonly/>')
876
+ .val( output )
877
+ .appendTo( hiddenDiv );
878
+
879
+ // For browsers that support the copy execCommand, try to use it
880
+ if ( document.queryCommandSupported('copy') ) {
881
+ hiddenDiv.appendTo( dt.table().container() );
882
+ textarea[0].focus();
883
+ textarea[0].select();
884
+
885
+ try {
886
+ var successful = document.execCommand( 'copy' );
887
+ hiddenDiv.remove();
888
+
889
+ if (successful) {
890
+ dt.buttons.info(
891
+ dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
892
+ dt.i18n( 'buttons.copySuccess', {
893
+ 1: 'Copied one row to clipboard',
894
+ _: 'Copied %d rows to clipboard'
895
+ }, exportData.rows ),
896
+ 2000
897
+ );
898
+ return;
899
+ }
900
+ }
901
+ catch (t) {}
902
+ }
903
+
904
+ // Otherwise we show the text box and instruct the user to use it
905
+ var message = $('<span>'+dt.i18n( 'buttons.copyKeys',
906
+ 'Press <i>ctrl</i> or <i>\u2318</i> + <i>C</i> to copy the table data<br>to your system clipboard.<br><br>'+
907
+ 'To cancel, click this message or press escape.' )+'</span>'
908
+ )
909
+ .append( hiddenDiv );
910
+
911
+ dt.buttons.info( dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ), message, 0 );
912
+
913
+ // Select the text so when the user activates their system clipboard
914
+ // it will copy that text
915
+ textarea[0].focus();
916
+ textarea[0].select();
917
+
918
+ // Event to hide the message when the user is done
919
+ var container = $(message).closest('.dt-button-info');
920
+ var close = function () {
921
+ container.off( 'click.buttons-copy' );
922
+ $(document).off( '.buttons-copy' );
923
+ dt.buttons.info( false );
924
+ };
925
+
926
+ container.on( 'click.buttons-copy', close );
927
+ $(document)
928
+ .on( 'keydown.buttons-copy', function (e) {
929
+ if ( e.keyCode === 27 ) { // esc
930
+ close();
931
+ }
932
+ } )
933
+ .on( 'copy.buttons-copy cut.buttons-copy', function () {
934
+ close();
935
+ } );
936
+ },
937
+
938
+ exportOptions: {},
939
+
940
+ fieldSeparator: '\t',
941
+
942
+ fieldBoundary: '',
943
+
944
+ header: true,
945
+
946
+ footer: false
538
947
  };
539
948
 
540
949
  //
541
950
  // CSV export
542
951
  //
543
952
  DataTable.ext.buttons.csvHtml5 = {
544
- className: 'buttons-csv buttons-html5',
953
+ bom: false,
954
+
955
+ className: 'buttons-csv buttons-html5',
545
956
 
546
- available: function () {
547
- return window.FileReader !== undefined && window.Blob;
548
- },
957
+ available: function () {
958
+ return window.FileReader !== undefined && window.Blob;
959
+ },
549
960
 
550
- text: function ( dt ) {
551
- return dt.i18n( 'buttons.csv', 'CSV' );
552
- },
961
+ text: function ( dt ) {
962
+ return dt.i18n( 'buttons.csv', 'CSV' );
963
+ },
553
964
 
554
- action: function ( e, dt, button, config ) {
555
- // Set the text
556
- var newLine = _newLine( config );
557
- var output = _exportData( dt, config ).str;
558
- var charset = config.charset;
965
+ action: function ( e, dt, button, config ) {
966
+ // Set the text
967
+ var output = _exportData( dt, config ).str;
968
+ var charset = config.charset;
559
969
 
560
- if ( charset !== false ) {
561
- if ( ! charset ) {
562
- charset = document.characterSet || document.charset;
563
- }
970
+ if ( config.customize ) {
971
+ output = config.customize( output, config );
972
+ }
564
973
 
565
- if ( charset ) {
566
- charset = ';charset='+charset;
567
- }
568
- }
569
- else {
570
- charset = '';
571
- }
974
+ if ( charset !== false ) {
975
+ if ( ! charset ) {
976
+ charset = document.characterSet || document.charset;
977
+ }
572
978
 
573
- _saveAs(
574
- new Blob( [output], {type: 'text/csv'+charset} ),
575
- _filename( config )
576
- );
577
- },
979
+ if ( charset ) {
980
+ charset = ';charset='+charset;
981
+ }
982
+ }
983
+ else {
984
+ charset = '';
985
+ }
578
986
 
579
- filename: '*',
987
+ if ( config.bom ) {
988
+ output = '\ufeff' + output;
989
+ }
580
990
 
581
- extension: '.csv',
991
+ _saveAs(
992
+ new Blob( [output], {type: 'text/csv'+charset} ),
993
+ _filename( config ),
994
+ true
995
+ );
996
+ },
582
997
 
583
- exportOptions: {},
998
+ filename: '*',
584
999
 
585
- fieldSeparator: ',',
1000
+ extension: '.csv',
586
1001
 
587
- fieldBoundary: '"',
1002
+ exportOptions: {},
588
1003
 
589
- escapeChar: '"',
1004
+ fieldSeparator: ',',
590
1005
 
591
- charset: null,
1006
+ fieldBoundary: '"',
592
1007
 
593
- header: true,
1008
+ escapeChar: '"',
594
1009
 
595
- footer: false
1010
+ charset: null,
1011
+
1012
+ header: true,
1013
+
1014
+ footer: false
596
1015
  };
597
1016
 
598
1017
  //
599
1018
  // Excel (xlsx) export
600
1019
  //
601
1020
  DataTable.ext.buttons.excelHtml5 = {
602
- className: 'buttons-excel buttons-html5',
603
-
604
- available: function () {
605
- return window.FileReader !== undefined && window.JSZip !== undefined && ! _isSafari();
606
- },
607
-
608
- text: function ( dt ) {
609
- return dt.i18n( 'buttons.excel', 'Excel' );
610
- },
611
-
612
- action: function ( e, dt, button, config ) {
613
- // Set the text
614
- var xml = '';
615
- var data = dt.buttons.exportData( config.exportOptions );
616
- var addRow = function ( row ) {
617
- var cells = [];
618
-
619
- for ( var i=0, ien=row.length ; i<ien ; i++ ) {
620
- if ( row[i] === null || row[i] === undefined ) {
621
- row[i] = '';
622
- }
623
-
624
- // Don't match numbers with leading zeros or a negative anywhere
625
- // but the start
626
- cells.push( typeof row[i] === 'number' || (row[i].match && row[i].match(/^-?[0-9\.]+$/) && row[i].charAt(0) !== '0') ?
627
- '<c t="n"><v>'+row[i]+'</v></c>' :
628
- '<c t="inlineStr"><is><t>'+(
629
- ! row[i].replace ?
630
- row[i] :
631
- row[i]
632
- .replace(/&(?!amp;)/g, '&amp;')
633
- .replace(/[\x00-\x1F\x7F-\x9F]/g, ''))+ // remove control characters
634
- '</t></is></c>' // they are not valid in XML
635
- );
636
- }
637
-
638
- return '<row>'+cells.join('')+'</row>';
639
- };
640
-
641
- if ( config.header ) {
642
- xml += addRow( data.header );
643
- }
644
-
645
- for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
646
- xml += addRow( data.body[i] );
647
- }
648
-
649
- if ( config.footer ) {
650
- xml += addRow( data.footer );
651
- }
652
-
653
- var zip = new window.JSZip();
654
- var _rels = zip.folder("_rels");
655
- var xl = zip.folder("xl");
656
- var xl_rels = zip.folder("xl/_rels");
657
- var xl_worksheets = zip.folder("xl/worksheets");
658
-
659
- zip.file( '[Content_Types].xml', excelStrings['[Content_Types].xml'] );
660
- _rels.file( '.rels', excelStrings['_rels/.rels'] );
661
- xl.file( 'workbook.xml', excelStrings['xl/workbook.xml'] );
662
- xl_rels.file( 'workbook.xml.rels', excelStrings['xl/_rels/workbook.xml.rels'] );
663
- xl_worksheets.file( 'sheet1.xml', excelStrings['xl/worksheets/sheet1.xml'].replace( '__DATA__', xml ) );
664
-
665
- _saveAs(
666
- zip.generate( {type:"blob"} ),
667
- _filename( config )
668
- );
669
- },
670
-
671
- filename: '*',
672
-
673
- extension: '.xlsx',
674
-
675
- exportOptions: {},
676
-
677
- header: true,
678
-
679
- footer: false
1021
+ className: 'buttons-excel buttons-html5',
1022
+
1023
+ available: function () {
1024
+ return window.FileReader !== undefined && _jsZip() !== undefined && ! _isSafari() && _serialiser;
1025
+ },
1026
+
1027
+ text: function ( dt ) {
1028
+ return dt.i18n( 'buttons.excel', 'Excel' );
1029
+ },
1030
+
1031
+ action: function ( e, dt, button, config ) {
1032
+ var rowPos = 0;
1033
+ var getXml = function ( type ) {
1034
+ var str = excelStrings[ type ];
1035
+
1036
+ //str = str.replace( /xmlns:/g, 'xmlns_' ).replace( /mc:/g, 'mc_' );
1037
+
1038
+ return $.parseXML( str );
1039
+ };
1040
+ var rels = getXml('xl/worksheets/sheet1.xml');
1041
+ var relsGet = rels.getElementsByTagName( "sheetData" )[0];
1042
+
1043
+ var xlsx = {
1044
+ _rels: {
1045
+ ".rels": getXml('_rels/.rels')
1046
+ },
1047
+ xl: {
1048
+ _rels: {
1049
+ "workbook.xml.rels": getXml('xl/_rels/workbook.xml.rels')
1050
+ },
1051
+ "workbook.xml": getXml('xl/workbook.xml'),
1052
+ "styles.xml": getXml('xl/styles.xml'),
1053
+ "worksheets": {
1054
+ "sheet1.xml": rels
1055
+ }
1056
+
1057
+ },
1058
+ "[Content_Types].xml": getXml('[Content_Types].xml')
1059
+ };
1060
+
1061
+ var data = dt.buttons.exportData( config.exportOptions );
1062
+ var currentRow, rowNode;
1063
+ var addRow = function ( row ) {
1064
+ currentRow = rowPos+1;
1065
+ rowNode = _createNode( rels, "row", { attr: {r:currentRow} } );
1066
+
1067
+ for ( var i=0, ien=row.length ; i<ien ; i++ ) {
1068
+ // Concat both the Cell Columns as a letter and the Row of the cell.
1069
+ var cellId = createCellPos(i) + '' + currentRow;
1070
+ var cell;
1071
+
1072
+ if ( row[i] === null || row[i] === undefined ) {
1073
+ row[i] = '';
1074
+ }
1075
+
1076
+ // Detect numbers - don't match numbers with leading zeros or a negative
1077
+ // anywhere but the start
1078
+ if ( typeof row[i] === 'number' || (
1079
+ row[i].match &&
1080
+ $.trim(row[i]).match(/^-?\d+(\.\d+)?$/) &&
1081
+ ! $.trim(row[i]).match(/^0\d+/) )
1082
+ ) {
1083
+ cell = _createNode( rels, 'c', {
1084
+ attr: {
1085
+ t: 'n',
1086
+ r: cellId
1087
+ },
1088
+ children: [
1089
+ _createNode( rels, 'v', { text: row[i] } )
1090
+ ]
1091
+ } );
1092
+ }
1093
+ else {
1094
+ // Replace non standard characters for text output
1095
+ var text = ! row[i].replace ?
1096
+ row[i] :
1097
+ row[i].replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
1098
+
1099
+ cell = _createNode( rels, 'c', {
1100
+ attr: {
1101
+ t: 'inlineStr',
1102
+ r: cellId
1103
+ },
1104
+ children:{
1105
+ row: _createNode( rels, 'is', {
1106
+ children: {
1107
+ row: _createNode( rels, 't', {
1108
+ text: text
1109
+ } )
1110
+ }
1111
+ } )
1112
+ }
1113
+ } );
1114
+ }
1115
+
1116
+ rowNode.appendChild( cell );
1117
+ }
1118
+ relsGet.appendChild(rowNode);
1119
+ rowPos++;
1120
+ };
1121
+
1122
+ $( 'sheets sheet', xlsx.xl['workbook.xml'] ).attr( 'name', _sheetname( config ) );
1123
+
1124
+ if ( config.customizeData ) {
1125
+ config.customizeData( data );
1126
+ }
1127
+
1128
+ if ( config.header ) {
1129
+ addRow( data.header, rowPos );
1130
+ $('row c', rels).attr( 's', '2' ); // bold
1131
+ }
1132
+
1133
+ for ( var n=0, ie=data.body.length ; n<ie ; n++ ) {
1134
+ addRow( data.body[n], rowPos );
1135
+ }
1136
+
1137
+ if ( config.footer && data.footer ) {
1138
+ addRow( data.footer, rowPos);
1139
+ $('row:last c', rels).attr( 's', '2' ); // bold
1140
+ }
1141
+
1142
+ // Set column widths
1143
+ var cols = _createNode( rels, 'cols' );
1144
+ $('worksheet', rels).prepend( cols );
1145
+
1146
+ for ( var i=0, ien=data.header.length ; i<ien ; i++ ) {
1147
+ cols.appendChild( _createNode( rels, 'col', {
1148
+ attr: {
1149
+ min: i+1,
1150
+ max: i+1,
1151
+ width: _excelColWidth( data, i ),
1152
+ customWidth: 1
1153
+ }
1154
+ } ) );
1155
+ }
1156
+
1157
+ // Let the developer customise the document if they want to
1158
+ if ( config.customize ) {
1159
+ config.customize( xlsx );
1160
+ }
1161
+
1162
+ var jszip = _jsZip();
1163
+ var zip = new jszip();
1164
+ var zipConfig = {
1165
+ type: 'blob',
1166
+ mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
1167
+ };
1168
+
1169
+ _addToZip( zip, xlsx );
1170
+
1171
+ if ( zip.generateAsync ) {
1172
+ // JSZip 3+
1173
+ zip
1174
+ .generateAsync( zipConfig )
1175
+ .then( function ( blob ) {
1176
+ _saveAs( blob, _filename( config ) );
1177
+ } );
1178
+ }
1179
+ else {
1180
+ // JSZip 2.5
1181
+ _saveAs(
1182
+ zip.generate( zipConfig ),
1183
+ _filename( config )
1184
+ );
1185
+ }
1186
+ },
1187
+
1188
+ filename: '*',
1189
+
1190
+ extension: '.xlsx',
1191
+
1192
+ exportOptions: {},
1193
+
1194
+ header: true,
1195
+
1196
+ footer: false
680
1197
  };
681
1198
 
682
1199
  //
683
1200
  // PDF export - using pdfMake - http://pdfmake.org
684
1201
  //
685
1202
  DataTable.ext.buttons.pdfHtml5 = {
686
- className: 'buttons-pdf buttons-html5',
687
-
688
- available: function () {
689
- return window.FileReader !== undefined && window.pdfMake;
690
- },
691
-
692
- text: function ( dt ) {
693
- return dt.i18n( 'buttons.pdf', 'PDF' );
694
- },
695
-
696
- action: function ( e, dt, button, config ) {
697
- var newLine = _newLine( config );
698
- var data = dt.buttons.exportData( config.exportOptions );
699
- var rows = [];
700
-
701
- if ( config.header ) {
702
- rows.push( $.map( data.header, function ( d ) {
703
- return {
704
- text: typeof d === 'string' ? d : d+'',
705
- style: 'tableHeader'
706
- };
707
- } ) );
708
- }
709
-
710
- for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
711
- rows.push( $.map( data.body[i], function ( d ) {
712
- return {
713
- text: typeof d === 'string' ? d : d+'',
714
- style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'
715
- };
716
- } ) );
717
- }
718
-
719
- if ( config.footer ) {
720
- rows.push( $.map( data.footer, function ( d ) {
721
- return {
722
- text: typeof d === 'string' ? d : d+'',
723
- style: 'tableFooter'
724
- };
725
- } ) );
726
- }
727
-
728
- var doc = {
729
- pageSize: config.pageSize,
730
- pageOrientation: config.orientation,
731
- content: [
732
- {
733
- table: {
734
- headerRows: 1,
735
- body: rows
736
- },
737
- layout: 'noBorders'
738
- }
739
- ],
740
- styles: {
741
- tableHeader: {
742
- bold: true,
743
- fontSize: 11,
744
- color: 'white',
745
- fillColor: '#2d4154',
746
- alignment: 'center'
747
- },
748
- tableBodyEven: {},
749
- tableBodyOdd: {
750
- fillColor: '#f3f3f3'
751
- },
752
- tableFooter: {
753
- bold: true,
754
- fontSize: 11,
755
- color: 'white',
756
- fillColor: '#2d4154'
757
- },
758
- title: {
759
- alignment: 'center',
760
- fontSize: 15
761
- },
762
- message: {}
763
- },
764
- defaultStyle: {
765
- fontSize: 10
766
- }
767
- };
768
-
769
- if ( config.message ) {
1203
+ className: 'buttons-pdf buttons-html5',
1204
+
1205
+ available: function () {
1206
+ return window.FileReader !== undefined && _pdfMake();
1207
+ },
1208
+
1209
+ text: function ( dt ) {
1210
+ return dt.i18n( 'buttons.pdf', 'PDF' );
1211
+ },
1212
+
1213
+ action: function ( e, dt, button, config ) {
1214
+ var newLine = _newLine( config );
1215
+ var data = dt.buttons.exportData( config.exportOptions );
1216
+ var rows = [];
1217
+
1218
+ if ( config.header ) {
1219
+ rows.push( $.map( data.header, function ( d ) {
1220
+ return {
1221
+ text: typeof d === 'string' ? d : d+'',
1222
+ style: 'tableHeader'
1223
+ };
1224
+ } ) );
1225
+ }
1226
+
1227
+ for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
1228
+ rows.push( $.map( data.body[i], function ( d ) {
1229
+ return {
1230
+ text: typeof d === 'string' ? d : d+'',
1231
+ style: i % 2 ? 'tableBodyEven' : 'tableBodyOdd'
1232
+ };
1233
+ } ) );
1234
+ }
1235
+
1236
+ if ( config.footer && data.footer) {
1237
+ rows.push( $.map( data.footer, function ( d ) {
1238
+ return {
1239
+ text: typeof d === 'string' ? d : d+'',
1240
+ style: 'tableFooter'
1241
+ };
1242
+ } ) );
1243
+ }
1244
+
1245
+ var doc = {
1246
+ pageSize: config.pageSize,
1247
+ pageOrientation: config.orientation,
1248
+ content: [
1249
+ {
1250
+ table: {
1251
+ headerRows: 1,
1252
+ body: rows
1253
+ },
1254
+ layout: 'noBorders'
1255
+ }
1256
+ ],
1257
+ styles: {
1258
+ tableHeader: {
1259
+ bold: true,
1260
+ fontSize: 11,
1261
+ color: 'white',
1262
+ fillColor: '#2d4154',
1263
+ alignment: 'center'
1264
+ },
1265
+ tableBodyEven: {},
1266
+ tableBodyOdd: {
1267
+ fillColor: '#f3f3f3'
1268
+ },
1269
+ tableFooter: {
1270
+ bold: true,
1271
+ fontSize: 11,
1272
+ color: 'white',
1273
+ fillColor: '#2d4154'
1274
+ },
1275
+ title: {
1276
+ alignment: 'center',
1277
+ fontSize: 15
1278
+ },
1279
+ message: {}
1280
+ },
1281
+ defaultStyle: {
1282
+ fontSize: 10
1283
+ }
1284
+ };
1285
+
1286
+ if ( config.message ) {
770
1287
  doc.content.unshift( {
771
- text: config.message,
1288
+ text: typeof config.message == 'function' ? config.message(dt, button, config) : config.message,
772
1289
  style: 'message',
773
1290
  margin: [ 0, 0, 0, 12 ]
774
1291
  } );
775
- }
1292
+ }
776
1293
 
777
- if ( config.title ) {
778
- doc.content.unshift( {
779
- text: _title( config, false ),
780
- style: 'title',
781
- margin: [ 0, 0, 0, 12 ]
782
- } );
783
- }
1294
+ if ( config.title ) {
1295
+ doc.content.unshift( {
1296
+ text: _title( config, false ),
1297
+ style: 'title',
1298
+ margin: [ 0, 0, 0, 12 ]
1299
+ } );
1300
+ }
784
1301
 
785
- if ( config.customize ) {
786
- config.customize( doc );
787
- }
1302
+ if ( config.customize ) {
1303
+ config.customize( doc, config );
1304
+ }
788
1305
 
789
- var pdf = window.pdfMake.createPdf( doc );
1306
+ var pdf = _pdfMake().createPdf( doc );
790
1307
 
791
- if ( config.download === 'open' && ! _isSafari() ) {
792
- pdf.open();
793
- }
794
- else {
795
- pdf.getBuffer( function (buffer) {
796
- var blob = new Blob( [buffer], {type:'application/pdf'} );
1308
+ if ( config.download === 'open' && ! _isSafari() ) {
1309
+ pdf.open();
1310
+ }
1311
+ else {
1312
+ pdf.getBuffer( function (buffer) {
1313
+ var blob = new Blob( [buffer], {type:'application/pdf'} );
797
1314
 
798
- _saveAs( blob, _filename( config ) );
799
- } );
800
- }
801
- },
1315
+ _saveAs( blob, _filename( config ) );
1316
+ } );
1317
+ }
1318
+ },
802
1319
 
803
- title: '*',
1320
+ title: '*',
804
1321
 
805
- filename: '*',
1322
+ filename: '*',
806
1323
 
807
- extension: '.pdf',
1324
+ extension: '.pdf',
808
1325
 
809
- exportOptions: {},
1326
+ exportOptions: {},
810
1327
 
811
- orientation: 'portrait',
1328
+ orientation: 'portrait',
812
1329
 
813
- pageSize: 'A4',
1330
+ pageSize: 'A4',
814
1331
 
815
- header: true,
1332
+ header: true,
816
1333
 
817
- footer: false,
1334
+ footer: false,
818
1335
 
819
- message: null,
1336
+ message: null,
820
1337
 
821
- customize: null,
1338
+ customize: null,
822
1339
 
823
- download: 'download'
1340
+ download: 'download'
824
1341
  };
825
1342
 
826
1343