buttons.flash.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. /*!
  2. * Flash export buttons for Buttons and DataTables.
  3. * 2015 SpryMedia Ltd - datatables.net/license
  4. *
  5. * ZeroClipbaord - MIT license
  6. * Copyright (c) 2012 Joseph Huckaby
  7. */
  8. (function( factory ){
  9. if ( typeof define === 'function' && define.amd ) {
  10. // AMD
  11. define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) {
  12. return factory( $, window, document );
  13. } );
  14. }
  15. else if ( typeof exports === 'object' ) {
  16. // CommonJS
  17. module.exports = function (root, $) {
  18. if ( ! root ) {
  19. root = window;
  20. }
  21. if ( ! $ || ! $.fn.dataTable ) {
  22. $ = require('datatables.net')(root, $).$;
  23. }
  24. if ( ! $.fn.dataTable.Buttons ) {
  25. require('datatables.net-buttons')(root, $);
  26. }
  27. return factory( $, root, root.document );
  28. };
  29. }
  30. else {
  31. // Browser
  32. factory( jQuery, window, document );
  33. }
  34. }(function( $, window, document, undefined ) {
  35. 'use strict';
  36. var DataTable = $.fn.dataTable;
  37. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  38. * ZeroClipboard dependency
  39. */
  40. /*
  41. * ZeroClipboard 1.0.4 with modifications
  42. * Author: Joseph Huckaby
  43. * License: MIT
  44. *
  45. * Copyright (c) 2012 Joseph Huckaby
  46. */
  47. var ZeroClipboard_TableTools = {
  48. version: "1.0.4-TableTools2",
  49. clients: {}, // registered upload clients on page, indexed by id
  50. moviePath: '', // URL to movie
  51. nextId: 1, // ID of next movie
  52. $: function(thingy) {
  53. // simple DOM lookup utility function
  54. if (typeof(thingy) == 'string') {
  55. thingy = document.getElementById(thingy);
  56. }
  57. if (!thingy.addClass) {
  58. // extend element with a few useful methods
  59. thingy.hide = function() { this.style.display = 'none'; };
  60. thingy.show = function() { this.style.display = ''; };
  61. thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
  62. thingy.removeClass = function(name) {
  63. this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
  64. };
  65. thingy.hasClass = function(name) {
  66. return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
  67. };
  68. }
  69. return thingy;
  70. },
  71. setMoviePath: function(path) {
  72. // set path to ZeroClipboard.swf
  73. this.moviePath = path;
  74. },
  75. dispatch: function(id, eventName, args) {
  76. // receive event from flash movie, send to client
  77. var client = this.clients[id];
  78. if (client) {
  79. client.receiveEvent(eventName, args);
  80. }
  81. },
  82. register: function(id, client) {
  83. // register new client to receive events
  84. this.clients[id] = client;
  85. },
  86. getDOMObjectPosition: function(obj) {
  87. // get absolute coordinates for dom element
  88. var info = {
  89. left: 0,
  90. top: 0,
  91. width: obj.width ? obj.width : obj.offsetWidth,
  92. height: obj.height ? obj.height : obj.offsetHeight
  93. };
  94. if ( obj.style.width !== "" ) {
  95. info.width = obj.style.width.replace("px","");
  96. }
  97. if ( obj.style.height !== "" ) {
  98. info.height = obj.style.height.replace("px","");
  99. }
  100. while (obj) {
  101. info.left += obj.offsetLeft;
  102. info.top += obj.offsetTop;
  103. obj = obj.offsetParent;
  104. }
  105. return info;
  106. },
  107. Client: function(elem) {
  108. // constructor for new simple upload client
  109. this.handlers = {};
  110. // unique ID
  111. this.id = ZeroClipboard_TableTools.nextId++;
  112. this.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id;
  113. // register client with singleton to receive flash events
  114. ZeroClipboard_TableTools.register(this.id, this);
  115. // create movie
  116. if (elem) {
  117. this.glue(elem);
  118. }
  119. }
  120. };
  121. ZeroClipboard_TableTools.Client.prototype = {
  122. id: 0, // unique ID for us
  123. ready: false, // whether movie is ready to receive events or not
  124. movie: null, // reference to movie object
  125. clipText: '', // text to copy to clipboard
  126. fileName: '', // default file save name
  127. action: 'copy', // action to perform
  128. handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
  129. cssEffects: true, // enable CSS mouse effects on dom container
  130. handlers: null, // user event handlers
  131. sized: false,
  132. sheetName: '', // default sheet name for excel export
  133. glue: function(elem, title) {
  134. // glue to DOM element
  135. // elem can be ID or actual DOM element object
  136. this.domElement = ZeroClipboard_TableTools.$(elem);
  137. // float just above object, or zIndex 99 if dom element isn't set
  138. var zIndex = 99;
  139. if (this.domElement.style.zIndex) {
  140. zIndex = parseInt(this.domElement.style.zIndex, 10) + 1;
  141. }
  142. // find X/Y position of domElement
  143. var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
  144. // create floating DIV above element
  145. this.div = document.createElement('div');
  146. var style = this.div.style;
  147. style.position = 'absolute';
  148. style.left = '0px';
  149. style.top = '0px';
  150. style.width = (box.width) + 'px';
  151. style.height = box.height + 'px';
  152. style.zIndex = zIndex;
  153. if ( typeof title != "undefined" && title !== "" ) {
  154. this.div.title = title;
  155. }
  156. if ( box.width !== 0 && box.height !== 0 ) {
  157. this.sized = true;
  158. }
  159. // style.backgroundColor = '#f00'; // debug
  160. if ( this.domElement ) {
  161. this.domElement.appendChild(this.div);
  162. this.div.innerHTML = this.getHTML( box.width, box.height ).replace(/&/g, '&');
  163. }
  164. },
  165. positionElement: function() {
  166. var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
  167. var style = this.div.style;
  168. style.position = 'absolute';
  169. //style.left = (this.domElement.offsetLeft)+'px';
  170. //style.top = this.domElement.offsetTop+'px';
  171. style.width = box.width + 'px';
  172. style.height = box.height + 'px';
  173. if ( box.width !== 0 && box.height !== 0 ) {
  174. this.sized = true;
  175. } else {
  176. return;
  177. }
  178. var flash = this.div.childNodes[0];
  179. flash.width = box.width;
  180. flash.height = box.height;
  181. },
  182. getHTML: function(width, height) {
  183. // return HTML for movie
  184. var html = '';
  185. var flashvars = 'id=' + this.id +
  186. '&width=' + width +
  187. '&height=' + height;
  188. if (navigator.userAgent.match(/MSIE/)) {
  189. // IE gets an OBJECT tag
  190. var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
  191. html += '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard_TableTools.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
  192. }
  193. else {
  194. // all other browsers get an EMBED tag
  195. html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard_TableTools.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
  196. }
  197. return html;
  198. },
  199. hide: function() {
  200. // temporarily hide floater offscreen
  201. if (this.div) {
  202. this.div.style.left = '-2000px';
  203. }
  204. },
  205. show: function() {
  206. // show ourselves after a call to hide()
  207. this.reposition();
  208. },
  209. destroy: function() {
  210. // destroy control and floater
  211. var that = this;
  212. if (this.domElement && this.div) {
  213. $(this.div).remove();
  214. this.domElement = null;
  215. this.div = null;
  216. $.each( ZeroClipboard_TableTools.clients, function ( id, client ) {
  217. if ( client === that ) {
  218. delete ZeroClipboard_TableTools.clients[ id ];
  219. }
  220. } );
  221. }
  222. },
  223. reposition: function(elem) {
  224. // reposition our floating div, optionally to new container
  225. // warning: container CANNOT change size, only position
  226. if (elem) {
  227. this.domElement = ZeroClipboard_TableTools.$(elem);
  228. if (!this.domElement) {
  229. this.hide();
  230. }
  231. }
  232. if (this.domElement && this.div) {
  233. var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
  234. var style = this.div.style;
  235. style.left = '' + box.left + 'px';
  236. style.top = '' + box.top + 'px';
  237. }
  238. },
  239. clearText: function() {
  240. // clear the text to be copy / saved
  241. this.clipText = '';
  242. if (this.ready) {
  243. this.movie.clearText();
  244. }
  245. },
  246. appendText: function(newText) {
  247. // append text to that which is to be copied / saved
  248. this.clipText += newText;
  249. if (this.ready) { this.movie.appendText(newText) ;}
  250. },
  251. setText: function(newText) {
  252. // set text to be copied to be copied / saved
  253. this.clipText = newText;
  254. if (this.ready) { this.movie.setText(newText) ;}
  255. },
  256. setFileName: function(newText) {
  257. // set the file name
  258. this.fileName = newText;
  259. if (this.ready) {
  260. this.movie.setFileName(newText);
  261. }
  262. },
  263. setSheetName: function(newText) {
  264. // set sheet name, for excel
  265. this.sheetName = newText;
  266. if (this.ready) {
  267. this.movie.setSheetName(newText);
  268. }
  269. },
  270. setAction: function(newText) {
  271. // set action (save or copy)
  272. this.action = newText;
  273. if (this.ready) {
  274. this.movie.setAction(newText);
  275. }
  276. },
  277. addEventListener: function(eventName, func) {
  278. // add user event listener for event
  279. // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
  280. eventName = eventName.toString().toLowerCase().replace(/^on/, '');
  281. if (!this.handlers[eventName]) {
  282. this.handlers[eventName] = [];
  283. }
  284. this.handlers[eventName].push(func);
  285. },
  286. setHandCursor: function(enabled) {
  287. // enable hand cursor (true), or default arrow cursor (false)
  288. this.handCursorEnabled = enabled;
  289. if (this.ready) {
  290. this.movie.setHandCursor(enabled);
  291. }
  292. },
  293. setCSSEffects: function(enabled) {
  294. // enable or disable CSS effects on DOM container
  295. this.cssEffects = !!enabled;
  296. },
  297. receiveEvent: function(eventName, args) {
  298. var self;
  299. // receive event from flash
  300. eventName = eventName.toString().toLowerCase().replace(/^on/, '');
  301. // special behavior for certain events
  302. switch (eventName) {
  303. case 'load':
  304. // movie claims it is ready, but in IE this isn't always the case...
  305. // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
  306. this.movie = document.getElementById(this.movieId);
  307. if (!this.movie) {
  308. self = this;
  309. setTimeout( function() { self.receiveEvent('load', null); }, 1 );
  310. return;
  311. }
  312. // firefox on pc needs a "kick" in order to set these in certain cases
  313. if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
  314. self = this;
  315. setTimeout( function() { self.receiveEvent('load', null); }, 100 );
  316. this.ready = true;
  317. return;
  318. }
  319. this.ready = true;
  320. this.movie.clearText();
  321. this.movie.appendText( this.clipText );
  322. this.movie.setFileName( this.fileName );
  323. this.movie.setAction( this.action );
  324. this.movie.setHandCursor( this.handCursorEnabled );
  325. break;
  326. case 'mouseover':
  327. if (this.domElement && this.cssEffects) {
  328. //this.domElement.addClass('hover');
  329. if (this.recoverActive) {
  330. this.domElement.addClass('active');
  331. }
  332. }
  333. break;
  334. case 'mouseout':
  335. if (this.domElement && this.cssEffects) {
  336. this.recoverActive = false;
  337. if (this.domElement.hasClass('active')) {
  338. this.domElement.removeClass('active');
  339. this.recoverActive = true;
  340. }
  341. //this.domElement.removeClass('hover');
  342. }
  343. break;
  344. case 'mousedown':
  345. if (this.domElement && this.cssEffects) {
  346. this.domElement.addClass('active');
  347. }
  348. break;
  349. case 'mouseup':
  350. if (this.domElement && this.cssEffects) {
  351. this.domElement.removeClass('active');
  352. this.recoverActive = false;
  353. }
  354. break;
  355. } // switch eventName
  356. if (this.handlers[eventName]) {
  357. for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
  358. var func = this.handlers[eventName][idx];
  359. if (typeof(func) == 'function') {
  360. // actual function reference
  361. func(this, args);
  362. }
  363. else if ((typeof(func) == 'object') && (func.length == 2)) {
  364. // PHP style object + method, i.e. [myObject, 'myMethod']
  365. func[0][ func[1] ](this, args);
  366. }
  367. else if (typeof(func) == 'string') {
  368. // name of function
  369. window[func](this, args);
  370. }
  371. } // foreach event handler defined
  372. } // user defined handler for event
  373. }
  374. };
  375. ZeroClipboard_TableTools.hasFlash = function ()
  376. {
  377. try {
  378. var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
  379. if (fo) {
  380. return true;
  381. }
  382. }
  383. catch (e) {
  384. if (
  385. navigator.mimeTypes &&
  386. navigator.mimeTypes['application/x-shockwave-flash'] !== undefined &&
  387. navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin
  388. ) {
  389. return true;
  390. }
  391. }
  392. return false;
  393. };
  394. // For the Flash binding to work, ZeroClipboard_TableTools must be on the global
  395. // object list
  396. window.ZeroClipboard_TableTools = ZeroClipboard_TableTools;
  397. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  398. * Local (private) functions
  399. */
  400. /**
  401. * If a Buttons instance is initlaised before it is placed into the DOM, Flash
  402. * won't be able to bind to it, so we need to wait until it is available, this
  403. * method abstracts that out.
  404. *
  405. * @param {ZeroClipboard} flash ZeroClipboard instance
  406. * @param {jQuery} node Button
  407. */
  408. var _glue = function ( flash, node )
  409. {
  410. var id = node.attr('id');
  411. if ( node.parents('html').length ) {
  412. flash.glue( node[0], '' );
  413. }
  414. else {
  415. setTimeout( function () {
  416. _glue( flash, node );
  417. }, 500 );
  418. }
  419. };
  420. /**
  421. * Get the file name for an exported file.
  422. *
  423. * @param {object} config Button configuration
  424. * @param {boolean} incExtension Include the file name extension
  425. */
  426. var _filename = function ( config, incExtension )
  427. {
  428. // Backwards compatibility
  429. var filename = config.filename === '*' && config.title !== '*' && config.title !== undefined ?
  430. config.title :
  431. config.filename;
  432. if ( typeof filename === 'function' ) {
  433. filename = filename();
  434. }
  435. if ( filename.indexOf( '*' ) !== -1 ) {
  436. filename = filename.replace( '*', $('title').text() );
  437. }
  438. // Strip characters which the OS will object to
  439. filename = filename.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
  440. return incExtension === undefined || incExtension === true ?
  441. filename+config.extension :
  442. filename;
  443. };
  444. /**
  445. * Get the sheet name for Excel exports.
  446. *
  447. * @param {object} config Button configuration
  448. */
  449. var _sheetname = function ( config )
  450. {
  451. var sheetName = 'Sheet1';
  452. if ( config.sheetName ) {
  453. sheetName = config.sheetName.replace(/[\[\]\*\/\\\?\:]/g, '');
  454. }
  455. return sheetName;
  456. };
  457. /**
  458. * Get the title for an exported file.
  459. *
  460. * @param {object} config Button configuration
  461. */
  462. var _title = function ( config )
  463. {
  464. var title = config.title;
  465. if ( typeof title === 'function' ) {
  466. title = title();
  467. }
  468. return title.indexOf( '*' ) !== -1 ?
  469. title.replace( '*', $('title').text() ) :
  470. title;
  471. };
  472. /**
  473. * Set the flash text. This has to be broken up into chunks as the Javascript /
  474. * Flash bridge has a size limit. There is no indication in the Flash
  475. * documentation what this is, and it probably depends upon the browser.
  476. * Experimentation shows that the point is around 50k when data starts to get
  477. * lost, so an 8K limit used here is safe.
  478. *
  479. * @param {ZeroClipboard} flash ZeroClipboard instance
  480. * @param {string} data Data to send to Flash
  481. */
  482. var _setText = function ( flash, data )
  483. {
  484. var parts = data.match(/[\s\S]{1,8192}/g) || [];
  485. flash.clearText();
  486. for ( var i=0, len=parts.length ; i<len ; i++ )
  487. {
  488. flash.appendText( parts[i] );
  489. }
  490. };
  491. /**
  492. * Get the newline character(s)
  493. *
  494. * @param {object} config Button configuration
  495. * @return {string} Newline character
  496. */
  497. var _newLine = function ( config )
  498. {
  499. return config.newline ?
  500. config.newline :
  501. navigator.userAgent.match(/Windows/) ?
  502. '\r\n' :
  503. '\n';
  504. };
  505. /**
  506. * Combine the data from the `buttons.exportData` method into a string that
  507. * will be used in the export file.
  508. *
  509. * @param {DataTable.Api} dt DataTables API instance
  510. * @param {object} config Button configuration
  511. * @return {object} The data to export
  512. */
  513. var _exportData = function ( dt, config )
  514. {
  515. var newLine = _newLine( config );
  516. var data = dt.buttons.exportData( config.exportOptions );
  517. var boundary = config.fieldBoundary;
  518. var separator = config.fieldSeparator;
  519. var reBoundary = new RegExp( boundary, 'g' );
  520. var escapeChar = config.escapeChar !== undefined ?
  521. config.escapeChar :
  522. '\\';
  523. var join = function ( a ) {
  524. var s = '';
  525. // If there is a field boundary, then we might need to escape it in
  526. // the source data
  527. for ( var i=0, ien=a.length ; i<ien ; i++ ) {
  528. if ( i > 0 ) {
  529. s += separator;
  530. }
  531. s += boundary ?
  532. boundary + ('' + a[i]).replace( reBoundary, escapeChar+boundary ) + boundary :
  533. a[i];
  534. }
  535. return s;
  536. };
  537. var header = config.header ? join( data.header )+newLine : '';
  538. var footer = config.footer && data.footer ? newLine+join( data.footer ) : '';
  539. var body = [];
  540. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  541. body.push( join( data.body[i] ) );
  542. }
  543. return {
  544. str: header + body.join( newLine ) + footer,
  545. rows: body.length
  546. };
  547. };
  548. // Basic initialisation for the buttons is common between them
  549. var flashButton = {
  550. available: function () {
  551. return ZeroClipboard_TableTools.hasFlash();
  552. },
  553. init: function ( dt, button, config ) {
  554. // Insert the Flash movie
  555. ZeroClipboard_TableTools.moviePath = DataTable.Buttons.swfPath;
  556. var flash = new ZeroClipboard_TableTools.Client();
  557. flash.setHandCursor( true );
  558. flash.addEventListener('mouseDown', function(client) {
  559. config._fromFlash = true;
  560. dt.button( button[0] ).trigger();
  561. config._fromFlash = false;
  562. } );
  563. _glue( flash, button );
  564. config._flash = flash;
  565. },
  566. destroy: function ( dt, button, config ) {
  567. config._flash.destroy();
  568. },
  569. fieldSeparator: ',',
  570. fieldBoundary: '"',
  571. exportOptions: {},
  572. title: '*',
  573. filename: '*',
  574. extension: '.csv',
  575. header: true,
  576. footer: false
  577. };
  578. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  579. * DataTables options and methods
  580. */
  581. // Set the default SWF path
  582. DataTable.Buttons.swfPath = '//cdn.datatables.net/buttons/1.0.0/swf/flashExport.swf';
  583. // Method to allow Flash buttons to be resized when made visible - as they are
  584. // of zero height and width if initialised hidden
  585. DataTable.Api.register( 'buttons.resize()', function () {
  586. $.each( ZeroClipboard_TableTools.clients, function ( i, client ) {
  587. if ( client.domElement !== undefined && client.domElement.parentNode ) {
  588. client.positionElement();
  589. }
  590. } );
  591. } );
  592. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  593. * Button definitions
  594. */
  595. // Copy to clipboard
  596. DataTable.ext.buttons.copyFlash = $.extend( {}, flashButton, {
  597. className: 'buttons-copy buttons-flash',
  598. text: function ( dt ) {
  599. return dt.i18n( 'buttons.copy', 'Copy' );
  600. },
  601. action: function ( e, dt, button, config ) {
  602. // Check that the trigger did actually occur due to a Flash activation
  603. if ( ! config._fromFlash ) {
  604. return;
  605. }
  606. var flash = config._flash;
  607. var data = _exportData( dt, config );
  608. var output = config.customize ?
  609. config.customize( data.str, config ) :
  610. data.str;
  611. flash.setAction( 'copy' );
  612. _setText( flash, output );
  613. dt.buttons.info(
  614. dt.i18n( 'buttons.copyTitle', 'Copy to clipboard' ),
  615. dt.i18n( 'buttons.copyInfo', {
  616. _: 'Copied %d rows to clipboard',
  617. 1: 'Copied 1 row to clipboard'
  618. }, data.rows ),
  619. 3000
  620. );
  621. },
  622. fieldSeparator: '\t',
  623. fieldBoundary: ''
  624. } );
  625. // CSV save file
  626. DataTable.ext.buttons.csvFlash = $.extend( {}, flashButton, {
  627. className: 'buttons-csv buttons-flash',
  628. text: function ( dt ) {
  629. return dt.i18n( 'buttons.csv', 'CSV' );
  630. },
  631. action: function ( e, dt, button, config ) {
  632. // Set the text
  633. var flash = config._flash;
  634. var data = _exportData( dt, config );
  635. var output = config.customize ?
  636. config.customize( data.str, config ) :
  637. data.str;
  638. flash.setAction( 'csv' );
  639. flash.setFileName( _filename( config ) );
  640. _setText( flash, output );
  641. },
  642. escapeChar: '"'
  643. } );
  644. // Excel save file - this is really a CSV file using UTF-8 that Excel can read
  645. DataTable.ext.buttons.excelFlash = $.extend( {}, flashButton, {
  646. className: 'buttons-excel buttons-flash',
  647. text: function ( dt ) {
  648. return dt.i18n( 'buttons.excel', 'Excel' );
  649. },
  650. action: function ( e, dt, button, config ) {
  651. // Set the text
  652. var xml = '';
  653. var flash = config._flash;
  654. var data = dt.buttons.exportData( config.exportOptions );
  655. var addRow = function ( row ) {
  656. var cells = [];
  657. for ( var i=0, ien=row.length ; i<ien ; i++ ) {
  658. if ( row[i] === null || row[i] === undefined ) {
  659. row[i] = '';
  660. }
  661. cells.push( typeof row[i] === 'number' || (row[i].match && $.trim(row[i]).match(/^-?\d+(\.\d+)?$/) && row[i].charAt(0) !== '0') ?
  662. '<c t="n"><v>'+row[i]+'</v></c>' :
  663. '<c t="inlineStr"><is><t>'+(
  664. ! row[i].replace ?
  665. row[i] :
  666. row[i]
  667. .replace(/&(?!amp;)/g, '&amp;')
  668. .replace(/</g, '&lt;')
  669. .replace(/>/g, '&gt;')
  670. .replace(/[\x00-\x1F\x7F-\x9F]/g, ''))+ // remove control characters
  671. '</t></is></c>' // they are not valid in XML
  672. );
  673. }
  674. return '<row>'+cells.join('')+'</row>';
  675. };
  676. if ( config.header ) {
  677. xml += addRow( data.header );
  678. }
  679. for ( var i=0, ien=data.body.length ; i<ien ; i++ ) {
  680. xml += addRow( data.body[i] );
  681. }
  682. if ( config.footer ) {
  683. xml += addRow( data.footer );
  684. }
  685. flash.setAction( 'excel' );
  686. flash.setFileName( _filename( config ) );
  687. flash.setSheetName( _sheetname( config ) );
  688. _setText( flash, xml );
  689. },
  690. extension: '.xlsx'
  691. } );
  692. // PDF export
  693. DataTable.ext.buttons.pdfFlash = $.extend( {}, flashButton, {
  694. className: 'buttons-pdf buttons-flash',
  695. text: function ( dt ) {
  696. return dt.i18n( 'buttons.pdf', 'PDF' );
  697. },
  698. action: function ( e, dt, button, config ) {
  699. // Set the text
  700. var flash = config._flash;
  701. var data = dt.buttons.exportData( config.exportOptions );
  702. var totalWidth = dt.table().node().offsetWidth;
  703. // Calculate the column width ratios for layout of the table in the PDF
  704. var ratios = dt.columns( config.columns ).indexes().map( function ( idx ) {
  705. return dt.column( idx ).header().offsetWidth / totalWidth;
  706. } );
  707. flash.setAction( 'pdf' );
  708. flash.setFileName( _title( config ) );
  709. _setText( flash, JSON.stringify( {
  710. title: _filename(config, false),
  711. message: config.message,
  712. colWidth: ratios.toArray(),
  713. orientation: config.orientation,
  714. size: config.pageSize,
  715. header: config.header ? data.header : null,
  716. footer: config.footer ? data.footer : null,
  717. body: data.body
  718. } ) );
  719. },
  720. extension: '.pdf',
  721. orientation: 'portrait',
  722. pageSize: 'A4',
  723. message: '',
  724. newline: '\n'
  725. } );
  726. return DataTable.Buttons;
  727. }));