effective_datatables 3.2.7 → 3.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef7002186c955ceea81788574da37e926dde317e
4
- data.tar.gz: e4bc57451595479713c11d423d2b21b22629eaae
3
+ metadata.gz: d15e87f91c336f09837c05c1cd19ae3eb109aa5c
4
+ data.tar.gz: 02baa43cac7e7ecb1b0dbdee89d22512e98af70a
5
5
  SHA512:
6
- metadata.gz: 07f99e9baa2ca960349e3fc42949cc14a679109d5156ec8990b7fca81ee24a5abd582a67b07bc2a476da9eb588fc04660944609065c7fc7eaae470d1ed2ebbe1
7
- data.tar.gz: 867adf502935e2db8dec3171e785ee70039d0a15844ebea9a2858584a2f3a27201f5ecd4bf3918ff9c7ef227b7489559f92c0a66965d22ed45cd1a204914a2f9
6
+ metadata.gz: 4df1c018bc13eb6bfe06a9309b52081dfe5f7840fc136a7d9b31d8ac06d8d1fde0c1ea1e66bbee7a3616238fba866f9eb572e3c75d7b8ffb451b33411e1dc4fb
7
+ data.tar.gz: 6daf450e7860fa17e318c1b29e65b3cad892eb3b94fc235186db44b3c31073c9c08621b3c9963b21a3bae29fc602dc54939645946df68ae34be87f7c8e79b4dd
@@ -49,7 +49,9 @@ $.extend( true, DataTable.Buttons.defaults, {
49
49
  className: 'dt-button-collection dropdown-menu',
50
50
  button: {
51
51
  tag: 'li',
52
- className: 'dt-button'
52
+ className: 'dt-button',
53
+ active: 'active',
54
+ disabled: 'disabled'
53
55
  },
54
56
  buttonLiner: {
55
57
  tag: 'a',
@@ -48,7 +48,8 @@ $.extend( DataTable.ext.buttons, {
48
48
  className: 'buttons-colvis',
49
49
  buttons: [ {
50
50
  extend: 'columnsToggle',
51
- columns: conf.columns
51
+ columns: conf.columns,
52
+ columnText: conf.columnText
52
53
  } ]
53
54
  };
54
55
  },
@@ -58,7 +59,8 @@ $.extend( DataTable.ext.buttons, {
58
59
  var columns = dt.columns( conf.columns ).indexes().map( function ( idx ) {
59
60
  return {
60
61
  extend: 'columnToggle',
61
- columns: idx
62
+ columns: idx,
63
+ columnText: conf.columnText
62
64
  };
63
65
  } ).toArray();
64
66
 
@@ -69,7 +71,8 @@ $.extend( DataTable.ext.buttons, {
69
71
  columnToggle: function ( dt, conf ) {
70
72
  return {
71
73
  extend: 'columnVisibility',
72
- columns: conf.columns
74
+ columns: conf.columns,
75
+ columnText: conf.columnText
73
76
  };
74
77
  },
75
78
 
@@ -79,7 +82,8 @@ $.extend( DataTable.ext.buttons, {
79
82
  return {
80
83
  extend: 'columnVisibility',
81
84
  columns: idx,
82
- visibility: conf.visibility
85
+ visibility: conf.visibility,
86
+ columnText: conf.columnText
83
87
  };
84
88
  } ).toArray();
85
89
 
@@ -90,7 +94,7 @@ $.extend( DataTable.ext.buttons, {
90
94
  columnVisibility: {
91
95
  columns: undefined, // column selector
92
96
  text: function ( dt, button, conf ) {
93
- return conf._columnText( dt, conf.columns );
97
+ return conf._columnText( dt, conf );
94
98
  },
95
99
  className: 'buttons-columnVisibility',
96
100
  action: function ( e, dt, button, conf ) {
@@ -107,7 +111,7 @@ $.extend( DataTable.ext.buttons, {
107
111
 
108
112
  dt
109
113
  .on( 'column-visibility.dt'+conf.namespace, function (e, settings) {
110
- if ( ! settings.bDestroying ) {
114
+ if ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) {
111
115
  that.active( dt.column( conf.columns ).visible() );
112
116
  }
113
117
  } )
@@ -124,7 +128,7 @@ $.extend( DataTable.ext.buttons, {
124
128
 
125
129
  var col = dt.column( conf.columns );
126
130
 
127
- that.text( conf._columnText( dt, conf.columns ) );
131
+ that.text( conf._columnText( dt, conf ) );
128
132
  that.active( col.visible() );
129
133
  } );
130
134
 
@@ -136,16 +140,21 @@ $.extend( DataTable.ext.buttons, {
136
140
  .off( 'column-reorder.dt'+conf.namespace );
137
141
  },
138
142
 
139
- _columnText: function ( dt, col ) {
143
+ _columnText: function ( dt, conf ) {
140
144
  // Use DataTables' internal data structure until this is presented
141
145
  // is a public API. The other option is to use
142
146
  // `$( column(col).node() ).text()` but the node might not have been
143
147
  // populated when Buttons is constructed.
144
- var idx = dt.column( col ).index();
145
- return dt.settings()[0].aoColumns[ idx ].sTitle
148
+ var idx = dt.column( conf.columns ).index();
149
+ var title = dt.settings()[0].aoColumns[ idx ].sTitle
146
150
  .replace(/\n/g," ") // remove new lines
151
+ .replace(/<br\s*\/?>/gi, " ") // replace line breaks with spaces
147
152
  .replace( /<.*?>/g, "" ) // strip HTML
148
153
  .replace(/^\s+|\s+$/g,""); // trim
154
+
155
+ return conf.columnText ?
156
+ conf.columnText( dt, idx, title ) :
157
+ title;
149
158
  }
150
159
  },
151
160
 
@@ -228,35 +228,6 @@ DataTable.fileSave = _saveAs;
228
228
  * Local (private) functions
229
229
  */
230
230
 
231
- /**
232
- * Get the file name for an exported file.
233
- *
234
- * @param {object} config Button configuration
235
- * @param {boolean} incExtension Include the file name extension
236
- */
237
- var _filename = function ( config, incExtension )
238
- {
239
- // Backwards compatibility
240
- var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined ?
241
- config.title :
242
- config.filename;
243
-
244
- if ( typeof filename === 'function' ) {
245
- filename = filename();
246
- }
247
-
248
- if ( filename.indexOf( '*' ) !== -1 ) {
249
- filename = $.trim( filename.replace( '*', $('title').text() ) );
250
- }
251
-
252
- // Strip characters which the OS will object to
253
- filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
254
-
255
- return incExtension === undefined || incExtension === true ?
256
- filename+config.extension :
257
- filename;
258
- };
259
-
260
231
  /**
261
232
  * Get the sheet name for Excel exports.
262
233
  *
@@ -270,25 +241,7 @@ var _sheetname = function ( config )
270
241
  sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
271
242
  }
272
243
 
273
- return sheetName;
274
- };
275
-
276
- /**
277
- * Get the title for an exported file.
278
- *
279
- * @param {object} config Button configuration
280
- */
281
- var _title = function ( config )
282
- {
283
- var title = config.title;
284
-
285
- if ( typeof title === 'function' ) {
286
- title = title();
287
- }
288
-
289
- return title.indexOf( '*' ) !== -1 ?
290
- title.replace( '*', $('title').text() || 'Exported data' ) :
291
- title;
244
+ return sheetName;
292
245
  };
293
246
 
294
247
  /**
@@ -473,7 +426,7 @@ function _addToZip( zip, obj ) {
473
426
 
474
427
  // Safari, IE and Edge will put empty name space attributes onto
475
428
  // various elements making them useless. This strips them out
476
- str = str.replace( /<(.*?) xmlns=""(.*?)>/g, '<$1 $2>' );
429
+ str = str.replace( /<([^<>]*?) xmlns=""([^<>]*?)>/g, '<$1 $2>' );
477
430
 
478
431
  zip.file( name, str );
479
432
  }
@@ -498,13 +451,13 @@ function _createNode( doc, nodeName, opts ) {
498
451
  $(tempNode).attr( opts.attr );
499
452
  }
500
453
 
501
- if( opts.children ) {
454
+ if ( opts.children ) {
502
455
  $.each( opts.children, function ( key, value ) {
503
456
  tempNode.appendChild( value );
504
- });
457
+ } );
505
458
  }
506
459
 
507
- if( opts.text ) {
460
+ if ( opts.text !== null && opts.text !== undefined ) {
508
461
  tempNode.appendChild( doc.createTextNode( opts.text ) );
509
462
  }
510
463
  }
@@ -527,7 +480,10 @@ function _excelColWidth( data, col ) {
527
480
  }
528
481
 
529
482
  for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
530
- str = data.body[i][col].toString();
483
+ var point = data.body[i][col];
484
+ str = point !== null && point !== undefined ?
485
+ point.toString() :
486
+ '';
531
487
 
532
488
  // If there is a newline character, workout the width of the column
533
489
  // based on the longest line in the string
@@ -549,7 +505,7 @@ function _excelColWidth( data, col ) {
549
505
 
550
506
  // Max width rather than having potentially massive column widths
551
507
  if ( max > 40 ) {
552
- break;
508
+ return 52; // 40 * 1.3
553
509
  }
554
510
  }
555
511
 
@@ -602,6 +558,7 @@ var excelStrings = {
602
558
  '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'+
603
559
  '<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">'+
604
560
  '<sheetData/>'+
561
+ '<mergeCells count="0"/>'+
605
562
  '</worksheet>',
606
563
 
607
564
  "xl/styles.xml":
@@ -709,11 +666,11 @@ var excelStrings = {
709
666
  '<xf numFmtId="0" fontId="2" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
710
667
  '<xf numFmtId="0" fontId="3" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
711
668
  '<xf numFmtId="0" fontId="4" fillId="2" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
712
- '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
713
- '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
714
- '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
715
- '<xf numFmtId="0" fontId="3" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
716
- '<xf numFmtId="0" fontId="4" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
669
+ '<xf numFmtId="0" fontId="0" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
670
+ '<xf numFmtId="0" fontId="1" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
671
+ '<xf numFmtId="0" fontId="2" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
672
+ '<xf numFmtId="0" fontId="3" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
673
+ '<xf numFmtId="0" fontId="4" fillId="3" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
717
674
  '<xf numFmtId="0" fontId="0" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
718
675
  '<xf numFmtId="0" fontId="1" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
719
676
  '<xf numFmtId="0" fontId="2" fillId="4" borderId="0" applyFont="1" applyFill="1" applyBorder="1"/>'+
@@ -824,7 +781,12 @@ DataTable.ext.buttons.copyHtml5 = {
824
781
  },
825
782
 
826
783
  action: function ( e, dt, button, config ) {
784
+ this.processing( true );
785
+
786
+ var that = this;
827
787
  var exportData = _exportData( dt, config );
788
+ var info = dt.buttons.exportInfo( config );
789
+ var newline = _newLine(config);
828
790
  var output = exportData.str;
829
791
  var hiddenDiv = $('<div/>')
830
792
  .css( {
@@ -836,6 +798,18 @@ DataTable.ext.buttons.copyHtml5 = {
836
798
  left: 0
837
799
  } );
838
800
 
801
+ if ( info.title ) {
802
+ output = info.title + newline + newline + output;
803
+ }
804
+
805
+ if ( info.messageTop ) {
806
+ output = info.messageTop + newline + newline + output;
807
+ }
808
+
809
+ if ( info.messageBottom ) {
810
+ output = output + newline + newline + info.messageBottom;
811
+ }
812
+
839
813
  if ( config.customize ) {
840
814
  output = config.customize( output, config );
841
815
  }
@@ -863,6 +837,8 @@ DataTable.ext.buttons.copyHtml5 = {
863
837
  }, exportData.rows ),
864
838
  2000
865
839
  );
840
+
841
+ this.processing( false );
866
842
  return;
867
843
  }
868
844
  }
@@ -896,10 +872,12 @@ DataTable.ext.buttons.copyHtml5 = {
896
872
  .on( 'keydown.buttons-copy', function (e) {
897
873
  if ( e.keyCode === 27 ) { // esc
898
874
  close();
875
+ that.processing( false );
899
876
  }
900
877
  } )
901
878
  .on( 'copy.buttons-copy cut.buttons-copy', function () {
902
879
  close();
880
+ that.processing( false );
903
881
  } );
904
882
  },
905
883
 
@@ -911,7 +889,13 @@ DataTable.ext.buttons.copyHtml5 = {
911
889
 
912
890
  header: true,
913
891
 
914
- footer: false
892
+ footer: false,
893
+
894
+ title: '*',
895
+
896
+ messageTop: '*',
897
+
898
+ messageBottom: '*'
915
899
  };
916
900
 
917
901
  //
@@ -931,8 +915,11 @@ DataTable.ext.buttons.csvHtml5 = {
931
915
  },
932
916
 
933
917
  action: function ( e, dt, button, config ) {
918
+ this.processing( true );
919
+
934
920
  // Set the text
935
921
  var output = _exportData( dt, config ).str;
922
+ var info = dt.buttons.exportInfo(config);
936
923
  var charset = config.charset;
937
924
 
938
925
  if ( config.customize ) {
@@ -958,9 +945,11 @@ DataTable.ext.buttons.csvHtml5 = {
958
945
 
959
946
  _saveAs(
960
947
  new Blob( [output], {type: 'text/csv'+charset} ),
961
- _filename( config ),
948
+ info.filename,
962
949
  true
963
950
  );
951
+
952
+ this.processing( false );
964
953
  },
965
954
 
966
955
  filename: '*',
@@ -997,6 +986,9 @@ DataTable.ext.buttons.excelHtml5 = {
997
986
  },
998
987
 
999
988
  action: function ( e, dt, button, config ) {
989
+ this.processing( true );
990
+
991
+ var that = this;
1000
992
  var rowPos = 0;
1001
993
  var getXml = function ( type ) {
1002
994
  var str = excelStrings[ type ];
@@ -1048,7 +1040,10 @@ DataTable.ext.buttons.excelHtml5 = {
1048
1040
  for ( var j=0, jen=_excelSpecials.length ; j<jen ; j++ ) {
1049
1041
  var special = _excelSpecials[j];
1050
1042
 
1051
- if ( row[i].match && row[i].match( special.match ) ) {
1043
+ // TODO Need to provide the ability for the specials to say
1044
+ // if they are returning a string, since at the moment it is
1045
+ // assumed to be a number
1046
+ if ( row[i].match && ! row[i].match(/^0\d+/) && row[i].match( special.match ) ) {
1052
1047
  var val = row[i].replace(/[^\d\.\-]/g, '');
1053
1048
 
1054
1049
  if ( special.fmt ) {
@@ -1124,9 +1119,34 @@ DataTable.ext.buttons.excelHtml5 = {
1124
1119
  config.customizeData( data );
1125
1120
  }
1126
1121
 
1122
+ var mergeCells = function ( row, colspan ) {
1123
+ var mergeCells = $('mergeCells', rels);
1124
+
1125
+ mergeCells[0].appendChild( _createNode( rels, 'mergeCell', {
1126
+ attr: {
1127
+ ref: 'A'+row+':'+createCellPos(colspan)+row
1128
+ }
1129
+ } ) );
1130
+ mergeCells.attr( 'count', mergeCells.attr( 'count' )+1 );
1131
+ $('row:eq('+(row-1)+') c', rels).attr( 's', '51' ); // centre
1132
+ };
1133
+
1134
+ // Title and top messages
1135
+ var exportInfo = dt.buttons.exportInfo( config );
1136
+ if ( exportInfo.title ) {
1137
+ addRow( [exportInfo.title], rowPos );
1138
+ mergeCells( rowPos, data.header.length-1 );
1139
+ }
1140
+
1141
+ if ( exportInfo.messageTop ) {
1142
+ addRow( [exportInfo.messageTop], rowPos );
1143
+ mergeCells( rowPos, data.header.length-1 );
1144
+ }
1145
+
1146
+ // Table itself
1127
1147
  if ( config.header ) {
1128
1148
  addRow( data.header, rowPos );
1129
- $('row c', rels).attr( 's', '2' ); // bold
1149
+ $('row:last c', rels).attr( 's', '2' ); // bold
1130
1150
  }
1131
1151
 
1132
1152
  for ( var n=0, ie=data.body.length ; n<ie ; n++ ) {
@@ -1138,6 +1158,12 @@ DataTable.ext.buttons.excelHtml5 = {
1138
1158
  $('row:last c', rels).attr( 's', '2' ); // bold
1139
1159
  }
1140
1160
 
1161
+ // Below the table
1162
+ if ( exportInfo.messageBottom ) {
1163
+ addRow( [exportInfo.messageBottom], rowPos );
1164
+ mergeCells( rowPos, data.header.length-1 );
1165
+ }
1166
+
1141
1167
  // Set column widths
1142
1168
  var cols = _createNode( rels, 'cols' );
1143
1169
  $('worksheet', rels).prepend( cols );
@@ -1172,15 +1198,17 @@ DataTable.ext.buttons.excelHtml5 = {
1172
1198
  zip
1173
1199
  .generateAsync( zipConfig )
1174
1200
  .then( function ( blob ) {
1175
- _saveAs( blob, _filename( config ) );
1201
+ _saveAs( blob, exportInfo.filename );
1202
+ that.processing( false );
1176
1203
  } );
1177
1204
  }
1178
1205
  else {
1179
1206
  // JSZip 2.5
1180
1207
  _saveAs(
1181
1208
  zip.generate( zipConfig ),
1182
- _filename( config )
1209
+ exportInfo.filename
1183
1210
  );
1211
+ this.processing( false );
1184
1212
  }
1185
1213
  },
1186
1214
 
@@ -1192,7 +1220,13 @@ DataTable.ext.buttons.excelHtml5 = {
1192
1220
 
1193
1221
  header: true,
1194
1222
 
1195
- footer: false
1223
+ footer: false,
1224
+
1225
+ title: '*',
1226
+
1227
+ messageTop: '*',
1228
+
1229
+ messageBottom: '*'
1196
1230
  };
1197
1231
 
1198
1232
  //
@@ -1210,8 +1244,11 @@ DataTable.ext.buttons.pdfHtml5 = {
1210
1244
  },
1211
1245
 
1212
1246
  action: function ( e, dt, button, config ) {
1213
- var newLine = _newLine( config );
1247
+ this.processing( true );
1248
+
1249
+ var that = this;
1214
1250
  var data = dt.buttons.exportData( config.exportOptions );
1251
+ var info = dt.buttons.exportInfo( config );
1215
1252
  var rows = [];
1216
1253
 
1217
1254
  if ( config.header ) {
@@ -1282,17 +1319,25 @@ DataTable.ext.buttons.pdfHtml5 = {
1282
1319
  }
1283
1320
  };
1284
1321
 
1285
- if ( config.message ) {
1286
- doc.content.unshift( {
1287
- text: typeof config.message == 'function' ? config.message(dt, button, config) : config.message,
1288
- style: 'message',
1289
- margin: [ 0, 0, 0, 12 ]
1290
- } );
1322
+ if ( info.messageTop ) {
1323
+ doc.content.unshift( {
1324
+ text: info.messageTop,
1325
+ style: 'message',
1326
+ margin: [ 0, 0, 0, 12 ]
1327
+ } );
1291
1328
  }
1292
1329
 
1293
- if ( config.title ) {
1330
+ if ( info.messageBottom ) {
1331
+ doc.content.push( {
1332
+ text: info.messageBottom,
1333
+ style: 'message',
1334
+ margin: [ 0, 0, 0, 12 ]
1335
+ } );
1336
+ }
1337
+
1338
+ if ( info.title ) {
1294
1339
  doc.content.unshift( {
1295
- text: _title( config, false ),
1340
+ text: info.title,
1296
1341
  style: 'title',
1297
1342
  margin: [ 0, 0, 0, 12 ]
1298
1343
  } );
@@ -1306,12 +1351,14 @@ DataTable.ext.buttons.pdfHtml5 = {
1306
1351
 
1307
1352
  if ( config.download === 'open' && ! _isDuffSafari() ) {
1308
1353
  pdf.open();
1354
+ this.processing( false );
1309
1355
  }
1310
1356
  else {
1311
1357
  pdf.getBuffer( function (buffer) {
1312
1358
  var blob = new Blob( [buffer], {type:'application/pdf'} );
1313
1359
 
1314
- _saveAs( blob, _filename( config ) );
1360
+ _saveAs( blob, info.filename );
1361
+ that.processing( false );
1315
1362
  } );
1316
1363
  }
1317
1364
  },
@@ -1332,7 +1379,9 @@ DataTable.ext.buttons.pdfHtml5 = {
1332
1379
 
1333
1380
  footer: false,
1334
1381
 
1335
- message: null,
1382
+ messageTop: '*',
1383
+
1384
+ messageBottom: '*',
1336
1385
 
1337
1386
  customize: null,
1338
1387
 
@@ -40,30 +40,42 @@ var DataTable = $.fn.dataTable;
40
40
  var _link = document.createElement( 'a' );
41
41
 
42
42
  /**
43
- * Convert a `link` tag's URL from a relative to an absolute address so it will
44
- * work correctly in the popup window which has no base URL.
43
+ * Clone link and style tags, taking into account the need to change the source
44
+ * path.
45
45
  *
46
46
  * @param {node} el Element to convert
47
47
  */
48
- var _relToAbs = function( el ) {
48
+ var _styleToAbs = function( el ) {
49
49
  var url;
50
50
  var clone = $(el).clone()[0];
51
51
  var linkHost;
52
52
 
53
53
  if ( clone.nodeName.toLowerCase() === 'link' ) {
54
- _link.href = clone.href;
55
- linkHost = _link.host;
54
+ clone.href = _relToAbs( clone.href );
55
+ }
56
56
 
57
- // IE doesn't have a trailing slash on the host
58
- // Chrome has it on the pathname
59
- if ( linkHost.indexOf('/') === -1 && _link.pathname.indexOf('/') !== 0) {
60
- linkHost += '/';
61
- }
57
+ return clone.outerHTML;
58
+ };
62
59
 
63
- clone.href = _link.protocol+"//"+linkHost+_link.pathname+_link.search;
60
+ /**
61
+ * Convert a URL from a relative to an absolute address so it will work
62
+ * correctly in the popup window which has no base URL.
63
+ *
64
+ * @param {string} href URL
65
+ */
66
+ var _relToAbs = function( href ) {
67
+ // Assign to a link on the original page so the browser will do all the
68
+ // hard work of figuring out where the file actually is
69
+ _link.href = href;
70
+ var linkHost = _link.host;
71
+
72
+ // IE doesn't have a trailing slash on the host
73
+ // Chrome has it on the pathname
74
+ if ( linkHost.indexOf('/') === -1 && _link.pathname.indexOf('/') !== 0) {
75
+ linkHost += '/';
64
76
  }
65
77
 
66
- return clone.outerHTML;
78
+ return _link.protocol+"//"+linkHost+_link.pathname+_link.search;
67
79
  };
68
80
 
69
81
 
@@ -75,7 +87,11 @@ DataTable.ext.buttons.print = {
75
87
  },
76
88
 
77
89
  action: function ( e, dt, button, config ) {
78
- var data = dt.buttons.exportData( config.exportOptions );
90
+ var data = dt.buttons.exportData(
91
+ $.extend( {decodeEntities: false}, config.exportOptions ) // XSS protection
92
+ );
93
+ var exportInfo = dt.buttons.exportInfo( config );
94
+
79
95
  var addRow = function ( d, tag ) {
80
96
  var str = '<tr>';
81
97
 
@@ -102,28 +118,19 @@ DataTable.ext.buttons.print = {
102
118
  if ( config.footer && data.footer ) {
103
119
  html += '<tfoot>'+ addRow( data.footer, 'th' ) +'</tfoot>';
104
120
  }
121
+ html += '</table>';
105
122
 
106
123
  // Open a new window for the printable table
107
124
  var win = window.open( '', '' );
108
- var title = config.title;
109
-
110
- if ( typeof title === 'function' ) {
111
- title = title();
112
- }
113
-
114
- if ( title.indexOf( '*' ) !== -1 ) {
115
- title= title.replace( '*', $('title').text() );
116
- }
117
-
118
125
  win.document.close();
119
126
 
120
127
  // Inject the title and also a copy of the style and link tags from this
121
128
  // document so the table can retain its base styling. Note that we have
122
129
  // to use string manipulation as IE won't allow elements to be created
123
130
  // in the host document and then appended to the new window.
124
- var head = '<title>'+title+'</title>';
131
+ var head = '<title>'+exportInfo.title+'</title>';
125
132
  $('style, link').each( function () {
126
- head += _relToAbs( this );
133
+ head += _styleToAbs( this );
127
134
  } );
128
135
 
129
136
  try {
@@ -135,32 +142,35 @@ DataTable.ext.buttons.print = {
135
142
 
136
143
  // Inject the table and other surrounding information
137
144
  win.document.body.innerHTML =
138
- '<h1>'+title+'</h1>'+
139
- '<div>'+
140
- (typeof config.message === 'function' ?
141
- config.message( dt, button, config ) :
142
- config.message
143
- )+
144
- '</div>'+
145
- html;
145
+ '<h1>'+exportInfo.title+'</h1>'+
146
+ '<div>'+(exportInfo.messageTop || '')+'</div>'+
147
+ html+
148
+ '<div>'+(exportInfo.messageBottom || '')+'</div>';
146
149
 
147
150
  $(win.document.body).addClass('dt-print-view');
148
151
 
152
+ $('img', win.document.body).each( function ( i, img ) {
153
+ img.setAttribute( 'src', _relToAbs( img.getAttribute('src') ) );
154
+ } );
155
+
149
156
  if ( config.customize ) {
150
157
  config.customize( win );
151
158
  }
152
159
 
160
+ // Allow stylesheets time to load
153
161
  setTimeout( function () {
154
162
  if ( config.autoPrint ) {
155
163
  win.print(); // blocking - so close will not
156
164
  win.close(); // execute until this is done
157
165
  }
158
- }, 250 );
166
+ }, 1000 );
159
167
  },
160
168
 
161
169
  title: '*',
162
170
 
163
- message: '',
171
+ messageTop: '*',
172
+
173
+ messageBottom: '*',
164
174
 
165
175
  exportOptions: {},
166
176