OpenSencillo  2016.106
Long live the simplicity of PHP
 All Data Structures Namespaces Files Functions Pages
dataTables.tableTools.js
1 
28 /* Global scope for TableTools for backwards compatibility.
29  * Will be removed in 2.3
30  */
31 var TableTools;
32 
33 (function(window, document, undefined) {
34 
35 
36 var factory = function( $, DataTable ) {
37 "use strict";
38 
39 
40 //include ZeroClipboard.js
41 /* ZeroClipboard 1.0.4
42  * Author: Joseph Huckaby
43  */
44 
45 var ZeroClipboard_TableTools = {
46 
47  version: "1.0.4-TableTools2",
48  clients: {}, // registered upload clients on page, indexed by id
49  moviePath: '', // URL to movie
50  nextId: 1, // ID of next movie
51 
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 
72  setMoviePath: function(path) {
73  // set path to ZeroClipboard.swf
74  this.moviePath = path;
75  },
76 
77  dispatch: function(id, eventName, args) {
78  // receive event from flash movie, send to client
79  var client = this.clients[id];
80  if (client) {
81  client.receiveEvent(eventName, args);
82  }
83  },
84 
85  register: function(id, client) {
86  // register new client to receive events
87  this.clients[id] = client;
88  },
89 
90  getDOMObjectPosition: function(obj) {
91  // get absolute coordinates for dom element
92  var info = {
93  left: 0,
94  top: 0,
95  width: obj.width ? obj.width : obj.offsetWidth,
96  height: obj.height ? obj.height : obj.offsetHeight
97  };
98 
99  if ( obj.style.width !== "" ) {
100  info.width = obj.style.width.replace("px","");
101  }
102 
103  if ( obj.style.height !== "" ) {
104  info.height = obj.style.height.replace("px","");
105  }
106 
107  while (obj) {
108  info.left += obj.offsetLeft;
109  info.top += obj.offsetTop;
110  obj = obj.offsetParent;
111  }
112 
113  return info;
114  },
115 
116  Client: function(elem) {
117  // constructor for new simple upload client
118  this.handlers = {};
119 
120  // unique ID
121  this.id = ZeroClipboard_TableTools.nextId++;
122  this.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id;
123 
124  // register client with singleton to receive flash events
125  ZeroClipboard_TableTools.register(this.id, this);
126 
127  // create movie
128  if (elem) {
129  this.glue(elem);
130  }
131  }
132 };
133 
134 ZeroClipboard_TableTools.Client.prototype = {
135 
136  id: 0, // unique ID for us
137  ready: false, // whether movie is ready to receive events or not
138  movie: null, // reference to movie object
139  clipText: '', // text to copy to clipboard
140  fileName: '', // default file save name
141  action: 'copy', // action to perform
142  handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
143  cssEffects: true, // enable CSS mouse effects on dom container
144  handlers: null, // user event handlers
145  sized: false,
146 
147  glue: function(elem, title) {
148  // glue to DOM element
149  // elem can be ID or actual DOM element object
150  this.domElement = ZeroClipboard_TableTools.$(elem);
151 
152  // float just above object, or zIndex 99 if dom element isn't set
153  var zIndex = 99;
154  if (this.domElement.style.zIndex) {
155  zIndex = parseInt(this.domElement.style.zIndex, 10) + 1;
156  }
157 
158  // find X/Y position of domElement
159  var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
160 
161  // create floating DIV above element
162  this.div = document.createElement('div');
163  var style = this.div.style;
164  style.position = 'absolute';
165  style.left = '0px';
166  style.top = '0px';
167  style.width = (box.width) + 'px';
168  style.height = box.height + 'px';
169  style.zIndex = zIndex;
170 
171  if ( typeof title != "undefined" && title !== "" ) {
172  this.div.title = title;
173  }
174  if ( box.width !== 0 && box.height !== 0 ) {
175  this.sized = true;
176  }
177 
178  // style.backgroundColor = '#f00'; // debug
179  if ( this.domElement ) {
180  this.domElement.appendChild(this.div);
181  this.div.innerHTML = this.getHTML( box.width, box.height ).replace(/&/g, '&');
182  }
183  },
184 
185  positionElement: function() {
186  var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
187  var style = this.div.style;
188 
189  style.position = 'absolute';
190  //style.left = (this.domElement.offsetLeft)+'px';
191  //style.top = this.domElement.offsetTop+'px';
192  style.width = box.width + 'px';
193  style.height = box.height + 'px';
194 
195  if ( box.width !== 0 && box.height !== 0 ) {
196  this.sized = true;
197  } else {
198  return;
199  }
200 
201  var flash = this.div.childNodes[0];
202  flash.width = box.width;
203  flash.height = box.height;
204  },
205 
206  getHTML: function(width, height) {
207  // return HTML for movie
208  var html = '';
209  var flashvars = 'id=' + this.id +
210  '&width=' + width +
211  '&height=' + height;
212 
213  if (navigator.userAgent.match(/MSIE/)) {
214  // IE gets an OBJECT tag
215  var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
216  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>';
217  }
218  else {
219  // all other browsers get an EMBED tag
220  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" />';
221  }
222  return html;
223  },
224 
225  hide: function() {
226  // temporarily hide floater offscreen
227  if (this.div) {
228  this.div.style.left = '-2000px';
229  }
230  },
231 
232  show: function() {
233  // show ourselves after a call to hide()
234  this.reposition();
235  },
236 
237  destroy: function() {
238  // destroy control and floater
239  if (this.domElement && this.div) {
240  this.hide();
241  this.div.innerHTML = '';
242 
243  var body = document.getElementsByTagName('body')[0];
244  try { body.removeChild( this.div ); } catch(e) {}
245 
246  this.domElement = null;
247  this.div = null;
248  }
249  },
250 
251  reposition: function(elem) {
252  // reposition our floating div, optionally to new container
253  // warning: container CANNOT change size, only position
254  if (elem) {
255  this.domElement = ZeroClipboard_TableTools.$(elem);
256  if (!this.domElement) {
257  this.hide();
258  }
259  }
260 
261  if (this.domElement && this.div) {
262  var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
263  var style = this.div.style;
264  style.left = '' + box.left + 'px';
265  style.top = '' + box.top + 'px';
266  }
267  },
268 
269  clearText: function() {
270  // clear the text to be copy / saved
271  this.clipText = '';
272  if (this.ready) {
273  this.movie.clearText();
274  }
275  },
276 
277  appendText: function(newText) {
278  // append text to that which is to be copied / saved
279  this.clipText += newText;
280  if (this.ready) { this.movie.appendText(newText) ;}
281  },
282 
283  setText: function(newText) {
284  // set text to be copied to be copied / saved
285  this.clipText = newText;
286  if (this.ready) { this.movie.setText(newText) ;}
287  },
288 
289  setCharSet: function(charSet) {
290  // set the character set (UTF16LE or UTF8)
291  this.charSet = charSet;
292  if (this.ready) { this.movie.setCharSet(charSet) ;}
293  },
294 
295  setBomInc: function(bomInc) {
296  // set if the BOM should be included or not
297  this.incBom = bomInc;
298  if (this.ready) { this.movie.setBomInc(bomInc) ;}
299  },
300 
301  setFileName: function(newText) {
302  // set the file name
303  this.fileName = newText;
304  if (this.ready) {
305  this.movie.setFileName(newText);
306  }
307  },
308 
309  setAction: function(newText) {
310  // set action (save or copy)
311  this.action = newText;
312  if (this.ready) {
313  this.movie.setAction(newText);
314  }
315  },
316 
317  addEventListener: function(eventName, func) {
318  // add user event listener for event
319  // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
320  eventName = eventName.toString().toLowerCase().replace(/^on/, '');
321  if (!this.handlers[eventName]) {
322  this.handlers[eventName] = [];
323  }
324  this.handlers[eventName].push(func);
325  },
326 
327  setHandCursor: function(enabled) {
328  // enable hand cursor (true), or default arrow cursor (false)
329  this.handCursorEnabled = enabled;
330  if (this.ready) {
331  this.movie.setHandCursor(enabled);
332  }
333  },
334 
335  setCSSEffects: function(enabled) {
336  // enable or disable CSS effects on DOM container
337  this.cssEffects = !!enabled;
338  },
339 
340  receiveEvent: function(eventName, args) {
341  var self;
342 
343  // receive event from flash
344  eventName = eventName.toString().toLowerCase().replace(/^on/, '');
345 
346  // special behavior for certain events
347  switch (eventName) {
348  case 'load':
349  // movie claims it is ready, but in IE this isn't always the case...
350  // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
351  this.movie = document.getElementById(this.movieId);
352  if (!this.movie) {
353  self = this;
354  setTimeout( function() { self.receiveEvent('load', null); }, 1 );
355  return;
356  }
357 
358  // firefox on pc needs a "kick" in order to set these in certain cases
359  if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
360  self = this;
361  setTimeout( function() { self.receiveEvent('load', null); }, 100 );
362  this.ready = true;
363  return;
364  }
365 
366  this.ready = true;
367  this.movie.clearText();
368  this.movie.appendText( this.clipText );
369  this.movie.setFileName( this.fileName );
370  this.movie.setAction( this.action );
371  this.movie.setCharSet( this.charSet );
372  this.movie.setBomInc( this.incBom );
373  this.movie.setHandCursor( this.handCursorEnabled );
374  break;
375 
376  case 'mouseover':
377  if (this.domElement && this.cssEffects) {
378  //this.domElement.addClass('hover');
379  if (this.recoverActive) {
380  this.domElement.addClass('active');
381  }
382  }
383  break;
384 
385  case 'mouseout':
386  if (this.domElement && this.cssEffects) {
387  this.recoverActive = false;
388  if (this.domElement.hasClass('active')) {
389  this.domElement.removeClass('active');
390  this.recoverActive = true;
391  }
392  //this.domElement.removeClass('hover');
393  }
394  break;
395 
396  case 'mousedown':
397  if (this.domElement && this.cssEffects) {
398  this.domElement.addClass('active');
399  }
400  break;
401 
402  case 'mouseup':
403  if (this.domElement && this.cssEffects) {
404  this.domElement.removeClass('active');
405  this.recoverActive = false;
406  }
407  break;
408  } // switch eventName
409 
410  if (this.handlers[eventName]) {
411  for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
412  var func = this.handlers[eventName][idx];
413 
414  if (typeof(func) == 'function') {
415  // actual function reference
416  func(this, args);
417  }
418  else if ((typeof(func) == 'object') && (func.length == 2)) {
419  // PHP style object + method, i.e. [myObject, 'myMethod']
420  func[0][ func[1] ](this, args);
421  }
422  else if (typeof(func) == 'string') {
423  // name of function
424  window[func](this, args);
425  }
426  } // foreach event handler defined
427  } // user defined handler for event
428  }
429 
430 };
431 
432 // For the Flash binding to work, ZeroClipboard_TableTools must be on the global
433 // object list
434 window.ZeroClipboard_TableTools = ZeroClipboard_TableTools;
435 //include TableTools.js
436 /* TableTools
437  * 2009-2015 SpryMedia Ltd - datatables.net/license
438  */
439 
440 /*globals TableTools,ZeroClipboard_TableTools*/
441 
442 
443 (function($, window, document) {
444 
460 TableTools = function( oDT, oOpts )
461 {
462  /* Santiy check that we are a new instance */
463  if ( ! this instanceof TableTools )
464  {
465  alert( "Warning: TableTools must be initialised with the keyword 'new'" );
466  }
467 
468  // In 1.10 we can use the API to get the settings object from a number of
469  // sources
470  var dtSettings = $.fn.dataTable.Api ?
471  new $.fn.dataTable.Api( oDT ).settings()[0] :
472  oDT.fnSettings();
473 
474 
475  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
476  * Public class variables
477  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
478 
482  this.s = {
489  "that": this,
490 
497  "dt": dtSettings,
498 
502  "print": {
509  "saveStart": -1,
510 
517  "saveLength": -1,
518 
525  "saveScroll": -1,
526 
533  "funcEnd": function () {}
534  },
535 
542  "buttonCounter": 0,
543 
547  "select": {
554  "type": "",
555 
562  "selected": [],
563 
571  "preRowSelect": null,
572 
579  "postSelected": null,
580 
587  "postDeselected": null,
588 
595  "all": false,
596 
603  "selectedClass": ""
604  },
605 
612  "custom": {},
613 
620  "swfPath": "",
621 
628  "buttonSet": [],
629 
637  "master": false,
638 
643  "tags": {}
644  };
645 
646 
650  this.dom = {
657  "container": null,
658 
665  "table": null,
666 
670  "print": {
677  "hidden": [],
678 
685  "message": null
686  },
687 
691  "collection": {
698  "collection": null,
699 
706  "background": null
707  }
708  };
709 
714  this.classes = $.extend( true, {}, TableTools.classes );
715  if ( this.s.dt.bJUI )
716  {
717  $.extend( true, this.classes, TableTools.classes_themeroller );
718  }
719 
720 
721  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
722  * Public class methods
723  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
724 
730  this.fnSettings = function () {
731  return this.s;
732  };
733 
734 
735  /* Constructor logic */
736  if ( typeof oOpts == 'undefined' )
737  {
738  oOpts = {};
739  }
740 
741 
742  TableTools._aInstances.push( this );
743  this._fnConstruct( oOpts );
744 
745  return this;
746 };
747 
748 
749 
750 TableTools.prototype = {
751  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
752  * Public methods
753  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
754 
763  "fnGetSelected": function ( filtered )
764  {
765  var
766  out = [],
767  data = this.s.dt.aoData,
768  displayed = this.s.dt.aiDisplay,
769  i, iLen;
770 
771  if ( filtered )
772  {
773  // Only consider filtered rows
774  for ( i=0, iLen=displayed.length ; i<iLen ; i++ )
775  {
776  if ( data[ displayed[i] ]._DTTT_selected )
777  {
778  out.push( data[ displayed[i] ].nTr );
779  }
780  }
781  }
782  else
783  {
784  // Use all rows
785  for ( i=0, iLen=data.length ; i<iLen ; i++ )
786  {
787  if ( data[i]._DTTT_selected )
788  {
789  out.push( data[i].nTr );
790  }
791  }
792  }
793 
794  return out;
795  },
796 
797 
803  "fnGetSelectedData": function ()
804  {
805  var out = [];
806  var data=this.s.dt.aoData;
807  var i, iLen;
808 
809  for ( i=0, iLen=data.length ; i<iLen ; i++ )
810  {
811  if ( data[i]._DTTT_selected )
812  {
813  out.push( this.s.dt.oInstance.fnGetData(i) );
814  }
815  }
816 
817  return out;
818  },
819 
820 
829  "fnGetSelectedIndexes": function ( filtered )
830  {
831  var
832  out = [],
833  data = this.s.dt.aoData,
834  displayed = this.s.dt.aiDisplay,
835  i, iLen;
836 
837  if ( filtered )
838  {
839  // Only consider filtered rows
840  for ( i=0, iLen=displayed.length ; i<iLen ; i++ )
841  {
842  if ( data[ displayed[i] ]._DTTT_selected )
843  {
844  out.push( displayed[i] );
845  }
846  }
847  }
848  else
849  {
850  // Use all rows
851  for ( i=0, iLen=data.length ; i<iLen ; i++ )
852  {
853  if ( data[i]._DTTT_selected )
854  {
855  out.push( i );
856  }
857  }
858  }
859 
860  return out;
861  },
862 
863 
869  "fnIsSelected": function ( n )
870  {
871  var pos = this.s.dt.oInstance.fnGetPosition( n );
872  return (this.s.dt.aoData[pos]._DTTT_selected===true) ? true : false;
873  },
874 
875 
882  "fnSelectAll": function ( filtered )
883  {
884  this._fnRowSelect( filtered ?
885  this.s.dt.aiDisplay :
886  this.s.dt.aoData
887  );
888  },
889 
890 
897  "fnSelectNone": function ( filtered )
898  {
899  this._fnRowDeselect( this.fnGetSelectedIndexes(filtered) );
900  },
901 
902 
908  "fnSelect": function ( n )
909  {
910  if ( this.s.select.type == "single" )
911  {
912  this.fnSelectNone();
913  this._fnRowSelect( n );
914  }
915  else
916  {
917  this._fnRowSelect( n );
918  }
919  },
920 
921 
927  "fnDeselect": function ( n )
928  {
929  this._fnRowDeselect( n );
930  },
931 
932 
939  "fnGetTitle": function( oConfig )
940  {
941  var sTitle = "";
942  if ( typeof oConfig.sTitle != 'undefined' && oConfig.sTitle !== "" ) {
943  sTitle = oConfig.sTitle;
944  } else {
945  var anTitle = document.getElementsByTagName('title');
946  if ( anTitle.length > 0 )
947  {
948  sTitle = anTitle[0].innerHTML;
949  }
950  }
951 
952  /* Strip characters which the OS will object to - checking for UTF8 support in the scripting
953  * engine
954  */
955  if ( "\u00A1".toString().length < 4 ) {
956  return sTitle.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
957  } else {
958  return sTitle.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g, "");
959  }
960  },
961 
962 
970  "fnCalcColRatios": function ( oConfig )
971  {
972  var
973  aoCols = this.s.dt.aoColumns,
974  aColumnsInc = this._fnColumnTargets( oConfig.mColumns ),
975  aColWidths = [],
976  iWidth = 0, iTotal = 0, i, iLen;
977 
978  for ( i=0, iLen=aColumnsInc.length ; i<iLen ; i++ )
979  {
980  if ( aColumnsInc[i] )
981  {
982  iWidth = aoCols[i].nTh.offsetWidth;
983  iTotal += iWidth;
984  aColWidths.push( iWidth );
985  }
986  }
987 
988 
989  for ( i=0, iLen=aColWidths.length ; i<iLen ; i++ )
990  {
991  aColWidths[i] = aColWidths[i] / iTotal;
992  }
993 
994  return aColWidths.join('\t');
995  },
996 
997 
1003  "fnGetTableData": function ( oConfig )
1004  {
1005  /* In future this could be used to get data from a plain HTML source as well as DataTables */
1006  if ( this.s.dt )
1007  {
1008  return this._fnGetDataTablesData( oConfig );
1009  }
1010  },
1011 
1012 
1018  "fnSetText": function ( clip, text )
1019  {
1020  this._fnFlashSetText( clip, text );
1021  },
1022 
1023 
1029  "fnResizeButtons": function ()
1030  {
1031  for ( var cli in ZeroClipboard_TableTools.clients )
1032  {
1033  if ( cli )
1034  {
1035  var client = ZeroClipboard_TableTools.clients[cli];
1036  if ( typeof client.domElement != 'undefined' &&
1037  client.domElement.parentNode )
1038  {
1039  client.positionElement();
1040  }
1041  }
1042  }
1043  },
1044 
1045 
1049  "fnResizeRequired": function ()
1050  {
1051  for ( var cli in ZeroClipboard_TableTools.clients )
1052  {
1053  if ( cli )
1054  {
1055  var client = ZeroClipboard_TableTools.clients[cli];
1056  if ( typeof client.domElement != 'undefined' &&
1057  client.domElement.parentNode == this.dom.container &&
1058  client.sized === false )
1059  {
1060  return true;
1061  }
1062  }
1063  }
1064  return false;
1065  },
1066 
1067 
1079  "fnPrint": function ( bView, oConfig )
1080  {
1081  if ( oConfig === undefined )
1082  {
1083  oConfig = {};
1084  }
1085 
1086  if ( bView === undefined || bView )
1087  {
1088  this._fnPrintStart( oConfig );
1089  }
1090  else
1091  {
1092  this._fnPrintEnd();
1093  }
1094  },
1095 
1096 
1102  "fnInfo": function ( message, time ) {
1103  var info = $('<div/>')
1104  .addClass( this.classes.print.info )
1105  .html( message )
1106  .appendTo( 'body' );
1107 
1108  setTimeout( function() {
1109  info.fadeOut( "normal", function() {
1110  info.remove();
1111  } );
1112  }, time );
1113  },
1114 
1115 
1116 
1121  "fnContainer": function () {
1122  return this.dom.container;
1123  },
1124 
1125 
1126 
1127  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1128  * Private methods (they are of course public in JS, but recommended as private)
1129  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1130 
1138  "_fnConstruct": function ( oOpts )
1139  {
1140  var that = this;
1141 
1142  this._fnCustomiseSettings( oOpts );
1143 
1144  /* Container element */
1145  this.dom.container = document.createElement( this.s.tags.container );
1146  this.dom.container.className = this.classes.container;
1147 
1148  /* Row selection config */
1149  if ( this.s.select.type != 'none' )
1150  {
1151  this._fnRowSelectConfig();
1152  }
1153 
1154  /* Buttons */
1155  this._fnButtonDefinations( this.s.buttonSet, this.dom.container );
1156 
1157  /* Destructor */
1158  this.s.dt.aoDestroyCallback.push( {
1159  "sName": "TableTools",
1160  "fn": function () {
1161  $(that.s.dt.nTBody)
1162  .off( 'click.DTTT_Select', that.s.custom.sRowSelector )
1163  .off( 'mousedown.DTTT_Select', 'tr' )
1164  .off( 'mouseup.DTTT_Select', 'tr' );
1165 
1166  $.each( ZeroClipboard_TableTools.clients, function ( id, client ) {
1167  if ( client.domElement !== undefined &&
1168  $(client.domElement).parents( that.dom.container ).length )
1169  {
1170  console.log( 'delete', id );
1171  delete ZeroClipboard_TableTools.clients[ id ];
1172  }
1173  } );
1174 
1175  $(that.dom.container).empty();
1176 
1177  // Remove the instance
1178  var idx = $.inArray( that, TableTools._aInstances );
1179  if ( idx !== -1 ) {
1180  TableTools._aInstances.splice( idx, 1 );
1181  }
1182  }
1183  } );
1184  },
1185 
1186 
1194  "_fnCustomiseSettings": function ( oOpts )
1195  {
1196  /* Is this the master control instance or not? */
1197  if ( typeof this.s.dt._TableToolsInit == 'undefined' )
1198  {
1199  this.s.master = true;
1200  this.s.dt._TableToolsInit = true;
1201  }
1202 
1203  /* We can use the table node from comparisons to group controls */
1204  this.dom.table = this.s.dt.nTable;
1205 
1206  /* Clone the defaults and then the user options */
1207  this.s.custom = $.extend( {}, TableTools.DEFAULTS, oOpts );
1208 
1209  /* Flash file location */
1210  this.s.swfPath = this.s.custom.sSwfPath;
1211  if ( typeof ZeroClipboard_TableTools != 'undefined' )
1212  {
1213  ZeroClipboard_TableTools.moviePath = this.s.swfPath;
1214  }
1215 
1216  /* Table row selecting */
1217  this.s.select.type = this.s.custom.sRowSelect;
1218  this.s.select.preRowSelect = this.s.custom.fnPreRowSelect;
1219  this.s.select.postSelected = this.s.custom.fnRowSelected;
1220  this.s.select.postDeselected = this.s.custom.fnRowDeselected;
1221 
1222  // Backwards compatibility - allow the user to specify a custom class in the initialiser
1223  if ( this.s.custom.sSelectedClass )
1224  {
1225  this.classes.select.row = this.s.custom.sSelectedClass;
1226  }
1227 
1228  this.s.tags = this.s.custom.oTags;
1229 
1230  /* Button set */
1231  this.s.buttonSet = this.s.custom.aButtons;
1232  },
1233 
1234 
1244  "_fnButtonDefinations": function ( buttonSet, wrapper )
1245  {
1246  var buttonDef;
1247 
1248  for ( var i=0, iLen=buttonSet.length ; i<iLen ; i++ )
1249  {
1250  if ( typeof buttonSet[i] == "string" )
1251  {
1252  if ( typeof TableTools.BUTTONS[ buttonSet[i] ] == 'undefined' )
1253  {
1254  alert( "TableTools: Warning - unknown button type: "+buttonSet[i] );
1255  continue;
1256  }
1257  buttonDef = $.extend( {}, TableTools.BUTTONS[ buttonSet[i] ], true );
1258  }
1259  else
1260  {
1261  if ( typeof TableTools.BUTTONS[ buttonSet[i].sExtends ] == 'undefined' )
1262  {
1263  alert( "TableTools: Warning - unknown button type: "+buttonSet[i].sExtends );
1264  continue;
1265  }
1266  var o = $.extend( {}, TableTools.BUTTONS[ buttonSet[i].sExtends ], true );
1267  buttonDef = $.extend( o, buttonSet[i], true );
1268  }
1269 
1270  var button = this._fnCreateButton(
1271  buttonDef,
1272  $(wrapper).hasClass(this.classes.collection.container)
1273  );
1274 
1275  if ( button ) {
1276  wrapper.appendChild( button );
1277  }
1278  }
1279  },
1280 
1281 
1289  "_fnCreateButton": function ( oConfig, bCollectionButton )
1290  {
1291  var nButton = this._fnButtonBase( oConfig, bCollectionButton );
1292 
1293  if ( oConfig.sAction.match(/flash/) )
1294  {
1295  if ( ! this._fnHasFlash() ) {
1296  return false;
1297  }
1298 
1299  this._fnFlashConfig( nButton, oConfig );
1300  }
1301  else if ( oConfig.sAction == "text" )
1302  {
1303  this._fnTextConfig( nButton, oConfig );
1304  }
1305  else if ( oConfig.sAction == "div" )
1306  {
1307  this._fnTextConfig( nButton, oConfig );
1308  }
1309  else if ( oConfig.sAction == "collection" )
1310  {
1311  this._fnTextConfig( nButton, oConfig );
1312  this._fnCollectionConfig( nButton, oConfig );
1313  }
1314 
1315  if ( this.s.dt.iTabIndex !== -1 ) {
1316  $(nButton)
1317  .attr( 'tabindex', this.s.dt.iTabIndex )
1318  .attr( 'aria-controls', this.s.dt.sTableId )
1319  .on( 'keyup.DTTT', function (e) {
1320  // Trigger the click event on return key when focused.
1321  // Note that for Flash buttons this has no effect since we
1322  // can't programmatically trigger the Flash export
1323  if ( e.keyCode === 13 ) {
1324  e.stopPropagation();
1325 
1326  $(this).trigger( 'click' );
1327  }
1328  } )
1329  .on( 'mousedown.DTTT', function (e) {
1330  // On mousedown we want to stop the focus occurring on the
1331  // button, focus is used only for the keyboard navigation.
1332  // But using preventDefault for the flash buttons stops the
1333  // flash action. However, it is not the button that gets
1334  // focused but the flash element for flash buttons, so this
1335  // works
1336  if ( ! oConfig.sAction.match(/flash/) ) {
1337  e.preventDefault();
1338  }
1339  } );
1340  }
1341 
1342  return nButton;
1343  },
1344 
1345 
1353  "_fnButtonBase": function ( o, bCollectionButton )
1354  {
1355  var sTag, sLiner, sClass;
1356 
1357  if ( bCollectionButton )
1358  {
1359  sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.collection.button;
1360  sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.collection.liner;
1361  sClass = this.classes.collection.buttons.normal;
1362  }
1363  else
1364  {
1365  sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.button;
1366  sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.liner;
1367  sClass = this.classes.buttons.normal;
1368  }
1369 
1370  var
1371  nButton = document.createElement( sTag ),
1372  nSpan = document.createElement( sLiner ),
1373  masterS = this._fnGetMasterSettings();
1374 
1375  nButton.className = sClass+" "+o.sButtonClass;
1376  nButton.setAttribute('id', "ToolTables_"+this.s.dt.sInstance+"_"+masterS.buttonCounter );
1377  nButton.appendChild( nSpan );
1378  nSpan.innerHTML = o.sButtonText;
1379 
1380  masterS.buttonCounter++;
1381 
1382  return nButton;
1383  },
1384 
1385 
1394  "_fnGetMasterSettings": function ()
1395  {
1396  if ( this.s.master )
1397  {
1398  return this.s;
1399  }
1400  else
1401  {
1402  /* Look for the master which has the same DT as this one */
1403  var instances = TableTools._aInstances;
1404  for ( var i=0, iLen=instances.length ; i<iLen ; i++ )
1405  {
1406  if ( this.dom.table == instances[i].s.dt.nTable )
1407  {
1408  return instances[i].s;
1409  }
1410  }
1411  }
1412  },
1413 
1414 
1415 
1416  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1417  * Button collection functions
1418  */
1419 
1427  "_fnCollectionConfig": function ( nButton, oConfig )
1428  {
1429  var nHidden = document.createElement( this.s.tags.collection.container );
1430  nHidden.style.display = "none";
1431  nHidden.className = this.classes.collection.container;
1432  oConfig._collection = nHidden;
1433  document.body.appendChild( nHidden );
1434 
1435  this._fnButtonDefinations( oConfig.aButtons, nHidden );
1436  },
1437 
1438 
1446  "_fnCollectionShow": function ( nButton, oConfig )
1447  {
1448  var
1449  that = this,
1450  oPos = $(nButton).offset(),
1451  nHidden = oConfig._collection,
1452  iDivX = oPos.left,
1453  iDivY = oPos.top + $(nButton).outerHeight(),
1454  iWinHeight = $(window).height(), iDocHeight = $(document).height(),
1455  iWinWidth = $(window).width(), iDocWidth = $(document).width();
1456 
1457  nHidden.style.position = "absolute";
1458  nHidden.style.left = iDivX+"px";
1459  nHidden.style.top = iDivY+"px";
1460  nHidden.style.display = "block";
1461  $(nHidden).css('opacity',0);
1462 
1463  var nBackground = document.createElement('div');
1464  nBackground.style.position = "absolute";
1465  nBackground.style.left = "0px";
1466  nBackground.style.top = "0px";
1467  nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px";
1468  nBackground.style.width = ((iWinWidth>iDocWidth)? iWinWidth : iDocWidth) +"px";
1469  nBackground.className = this.classes.collection.background;
1470  $(nBackground).css('opacity',0);
1471 
1472  document.body.appendChild( nBackground );
1473  document.body.appendChild( nHidden );
1474 
1475  /* Visual corrections to try and keep the collection visible */
1476  var iDivWidth = $(nHidden).outerWidth();
1477  var iDivHeight = $(nHidden).outerHeight();
1478 
1479  if ( iDivX + iDivWidth > iDocWidth )
1480  {
1481  nHidden.style.left = (iDocWidth-iDivWidth)+"px";
1482  }
1483 
1484  if ( iDivY + iDivHeight > iDocHeight )
1485  {
1486  nHidden.style.top = (iDivY-iDivHeight-$(nButton).outerHeight())+"px";
1487  }
1488 
1489  this.dom.collection.collection = nHidden;
1490  this.dom.collection.background = nBackground;
1491 
1492  /* This results in a very small delay for the end user but it allows the animation to be
1493  * much smoother. If you don't want the animation, then the setTimeout can be removed
1494  */
1495  setTimeout( function () {
1496  $(nHidden).animate({"opacity": 1}, 500);
1497  $(nBackground).animate({"opacity": 0.25}, 500);
1498  }, 10 );
1499 
1500  /* Resize the buttons to the Flash contents fit */
1501  this.fnResizeButtons();
1502 
1503  /* Event handler to remove the collection display */
1504  $(nBackground).click( function () {
1505  that._fnCollectionHide.call( that, null, null );
1506  } );
1507  },
1508 
1509 
1517  "_fnCollectionHide": function ( nButton, oConfig )
1518  {
1519  if ( oConfig !== null && oConfig.sExtends == 'collection' )
1520  {
1521  return;
1522  }
1523 
1524  if ( this.dom.collection.collection !== null )
1525  {
1526  $(this.dom.collection.collection).animate({"opacity": 0}, 500, function (e) {
1527  this.style.display = "none";
1528  } );
1529 
1530  $(this.dom.collection.background).animate({"opacity": 0}, 500, function (e) {
1531  this.parentNode.removeChild( this );
1532  } );
1533 
1534  this.dom.collection.collection = null;
1535  this.dom.collection.background = null;
1536  }
1537  },
1538 
1539 
1540 
1541  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1542  * Row selection functions
1543  */
1544 
1551  "_fnRowSelectConfig": function ()
1552  {
1553  if ( this.s.master )
1554  {
1555  var
1556  that = this,
1557  i, iLen,
1558  dt = this.s.dt,
1559  aoOpenRows = this.s.dt.aoOpenRows;
1560 
1561  $(dt.nTable).addClass( this.classes.select.table );
1562 
1563  // When using OS style selection, we want to cancel the shift text
1564  // selection, but only when the shift key is used (so you can
1565  // actually still select text in the table)
1566  if ( this.s.select.type === 'os' ) {
1567  $(dt.nTBody).on( 'mousedown.DTTT_Select', 'tr', function(e) {
1568  if ( e.shiftKey ) {
1569 
1570  $(dt.nTBody)
1571  .css( '-moz-user-select', 'none' )
1572  .one('selectstart.DTTT_Select', 'tr', function () {
1573  return false;
1574  } );
1575  }
1576  } );
1577 
1578  $(dt.nTBody).on( 'mouseup.DTTT_Select', 'tr', function(e) {
1579  $(dt.nTBody).css( '-moz-user-select', '' );
1580  } );
1581  }
1582 
1583  // Row selection
1584  $(dt.nTBody).on( 'click.DTTT_Select', this.s.custom.sRowSelector, function(e) {
1585  var row = this.nodeName.toLowerCase() === 'tr' ?
1586  this :
1587  $(this).parents('tr')[0];
1588 
1589  var select = that.s.select;
1590  var pos = that.s.dt.oInstance.fnGetPosition( row );
1591 
1592  /* Sub-table must be ignored (odd that the selector won't do this with >) */
1593  if ( row.parentNode != dt.nTBody ) {
1594  return;
1595  }
1596 
1597  /* Check that we are actually working with a DataTables controlled row */
1598  if ( dt.oInstance.fnGetData(row) === null ) {
1599  return;
1600  }
1601 
1602  // Shift click, ctrl click and simple click handling to make
1603  // row selection a lot like a file system in desktop OSs
1604  if ( select.type == 'os' ) {
1605  if ( e.ctrlKey || e.metaKey ) {
1606  // Add or remove from the selection
1607  if ( that.fnIsSelected( row ) ) {
1608  that._fnRowDeselect( row, e );
1609  }
1610  else {
1611  that._fnRowSelect( row, e );
1612  }
1613  }
1614  else if ( e.shiftKey ) {
1615  // Add a range of rows, from the last selected row to
1616  // this one
1617  var rowIdxs = that.s.dt.aiDisplay.slice(); // visible rows
1618  var idx1 = $.inArray( select.lastRow, rowIdxs );
1619  var idx2 = $.inArray( pos, rowIdxs );
1620 
1621  if ( that.fnGetSelected().length === 0 || idx1 === -1 ) {
1622  // select from top to here - slightly odd, but both
1623  // Windows and Mac OS do this
1624  rowIdxs.splice( $.inArray( pos, rowIdxs )+1, rowIdxs.length );
1625  }
1626  else {
1627  // reverse so we can shift click 'up' as well as down
1628  if ( idx1 > idx2 ) {
1629  var tmp = idx2;
1630  idx2 = idx1;
1631  idx1 = tmp;
1632  }
1633 
1634  rowIdxs.splice( idx2+1, rowIdxs.length );
1635  rowIdxs.splice( 0, idx1 );
1636  }
1637 
1638  if ( ! that.fnIsSelected( row ) ) {
1639  // Select range
1640  that._fnRowSelect( rowIdxs, e );
1641  }
1642  else {
1643  // Deselect range - need to keep the clicked on row selected
1644  rowIdxs.splice( $.inArray( pos, rowIdxs ), 1 );
1645  that._fnRowDeselect( rowIdxs, e );
1646  }
1647  }
1648  else {
1649  // No cmd or shift click. Deselect current if selected,
1650  // or select this row only
1651  if ( that.fnIsSelected( row ) && that.fnGetSelected().length === 1 ) {
1652  that._fnRowDeselect( row, e );
1653  }
1654  else {
1655  that.fnSelectNone();
1656  that._fnRowSelect( row, e );
1657  }
1658  }
1659  }
1660  else if ( that.fnIsSelected( row ) ) {
1661  that._fnRowDeselect( row, e );
1662  }
1663  else if ( select.type == "single" ) {
1664  that.fnSelectNone();
1665  that._fnRowSelect( row, e );
1666  }
1667  else if ( select.type == "multi" ) {
1668  that._fnRowSelect( row, e );
1669  }
1670 
1671  select.lastRow = pos;
1672  } );//.on('selectstart', function () { return false; } );
1673 
1674  // Bind a listener to the DataTable for when new rows are created.
1675  // This allows rows to be visually selected when they should be and
1676  // deferred rendering is used.
1677  dt.oApi._fnCallbackReg( dt, 'aoRowCreatedCallback', function (tr, data, index) {
1678  if ( dt.aoData[index]._DTTT_selected ) {
1679  $(tr).addClass( that.classes.select.row );
1680  }
1681  }, 'TableTools-SelectAll' );
1682  }
1683  },
1684 
1690  "_fnRowSelect": function ( src, e )
1691  {
1692  var
1693  that = this,
1694  data = this._fnSelectData( src ),
1695  firstTr = data.length===0 ? null : data[0].nTr,
1696  anSelected = [],
1697  i, len;
1698 
1699  // Get all the rows that will be selected
1700  for ( i=0, len=data.length ; i<len ; i++ )
1701  {
1702  if ( data[i].nTr )
1703  {
1704  anSelected.push( data[i].nTr );
1705  }
1706  }
1707 
1708  // User defined pre-selection function
1709  if ( this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anSelected, true) )
1710  {
1711  return;
1712  }
1713 
1714  // Mark them as selected
1715  for ( i=0, len=data.length ; i<len ; i++ )
1716  {
1717  data[i]._DTTT_selected = true;
1718 
1719  if ( data[i].nTr )
1720  {
1721  $(data[i].nTr).addClass( that.classes.select.row );
1722  }
1723  }
1724 
1725  // Post-selection function
1726  if ( this.s.select.postSelected !== null )
1727  {
1728  this.s.select.postSelected.call( this, anSelected );
1729  }
1730 
1731  TableTools._fnEventDispatch( this, 'select', anSelected, true );
1732  },
1733 
1739  "_fnRowDeselect": function ( src, e )
1740  {
1741  var
1742  that = this,
1743  data = this._fnSelectData( src ),
1744  firstTr = data.length===0 ? null : data[0].nTr,
1745  anDeselectedTrs = [],
1746  i, len;
1747 
1748  // Get all the rows that will be deselected
1749  for ( i=0, len=data.length ; i<len ; i++ )
1750  {
1751  if ( data[i].nTr )
1752  {
1753  anDeselectedTrs.push( data[i].nTr );
1754  }
1755  }
1756 
1757  // User defined pre-selection function
1758  if ( this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anDeselectedTrs, false) )
1759  {
1760  return;
1761  }
1762 
1763  // Mark them as deselected
1764  for ( i=0, len=data.length ; i<len ; i++ )
1765  {
1766  data[i]._DTTT_selected = false;
1767 
1768  if ( data[i].nTr )
1769  {
1770  $(data[i].nTr).removeClass( that.classes.select.row );
1771  }
1772  }
1773 
1774  // Post-deselection function
1775  if ( this.s.select.postDeselected !== null )
1776  {
1777  this.s.select.postDeselected.call( this, anDeselectedTrs );
1778  }
1779 
1780  TableTools._fnEventDispatch( this, 'select', anDeselectedTrs, false );
1781  },
1782 
1790  "_fnSelectData": function ( src )
1791  {
1792  var out = [], pos, i, iLen;
1793 
1794  if ( src.nodeName )
1795  {
1796  // Single node
1797  pos = this.s.dt.oInstance.fnGetPosition( src );
1798  out.push( this.s.dt.aoData[pos] );
1799  }
1800  else if ( typeof src.length !== 'undefined' )
1801  {
1802  // jQuery object or an array of nodes, or aoData points
1803  for ( i=0, iLen=src.length ; i<iLen ; i++ )
1804  {
1805  if ( src[i].nodeName )
1806  {
1807  pos = this.s.dt.oInstance.fnGetPosition( src[i] );
1808  out.push( this.s.dt.aoData[pos] );
1809  }
1810  else if ( typeof src[i] === 'number' )
1811  {
1812  out.push( this.s.dt.aoData[ src[i] ] );
1813  }
1814  else
1815  {
1816  out.push( src[i] );
1817  }
1818  }
1819 
1820  return out;
1821  }
1822  else if ( typeof src === 'number' )
1823  {
1824  out.push(this.s.dt.aoData[src]);
1825  }
1826  else
1827  {
1828  // A single aoData point
1829  out.push( src );
1830  }
1831 
1832  return out;
1833  },
1834 
1835 
1836  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1837  * Text button functions
1838  */
1839 
1848  "_fnTextConfig": function ( nButton, oConfig )
1849  {
1850  var that = this;
1851 
1852  if ( oConfig.fnInit !== null )
1853  {
1854  oConfig.fnInit.call( this, nButton, oConfig );
1855  }
1856 
1857  if ( oConfig.sToolTip !== "" )
1858  {
1859  nButton.title = oConfig.sToolTip;
1860  }
1861 
1862  $(nButton).hover( function () {
1863  if ( oConfig.fnMouseover !== null )
1864  {
1865  oConfig.fnMouseover.call( this, nButton, oConfig, null );
1866  }
1867  }, function () {
1868  if ( oConfig.fnMouseout !== null )
1869  {
1870  oConfig.fnMouseout.call( this, nButton, oConfig, null );
1871  }
1872  } );
1873 
1874  if ( oConfig.fnSelect !== null )
1875  {
1876  TableTools._fnEventListen( this, 'select', function (n) {
1877  oConfig.fnSelect.call( that, nButton, oConfig, n );
1878  } );
1879  }
1880 
1881  $(nButton).click( function (e) {
1882  //e.preventDefault();
1883 
1884  if ( oConfig.fnClick !== null )
1885  {
1886  oConfig.fnClick.call( that, nButton, oConfig, null, e );
1887  }
1888 
1889  /* Provide a complete function to match the behaviour of the flash elements */
1890  if ( oConfig.fnComplete !== null )
1891  {
1892  oConfig.fnComplete.call( that, nButton, oConfig, null, null );
1893  }
1894 
1895  that._fnCollectionHide( nButton, oConfig );
1896  } );
1897  },
1898 
1899 
1900 
1901  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1902  * Flash button functions
1903  */
1904 
1911  "_fnHasFlash": function ()
1912  {
1913  try {
1914  var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
1915  if (fo) {
1916  return true;
1917  }
1918  }
1919  catch (e) {
1920  if (
1921  navigator.mimeTypes &&
1922  navigator.mimeTypes['application/x-shockwave-flash'] !== undefined &&
1923  navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin
1924  ) {
1925  return true;
1926  }
1927  }
1928 
1929  return false;
1930  },
1931 
1932 
1941  "_fnFlashConfig": function ( nButton, oConfig )
1942  {
1943  var that = this;
1944  var flash = new ZeroClipboard_TableTools.Client();
1945 
1946  if ( oConfig.fnInit !== null )
1947  {
1948  oConfig.fnInit.call( this, nButton, oConfig );
1949  }
1950 
1951  flash.setHandCursor( true );
1952 
1953  if ( oConfig.sAction == "flash_save" )
1954  {
1955  flash.setAction( 'save' );
1956  flash.setCharSet( (oConfig.sCharSet=="utf16le") ? 'UTF16LE' : 'UTF8' );
1957  flash.setBomInc( oConfig.bBomInc );
1958  flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) );
1959  }
1960  else if ( oConfig.sAction == "flash_pdf" )
1961  {
1962  flash.setAction( 'pdf' );
1963  flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) );
1964  }
1965  else
1966  {
1967  flash.setAction( 'copy' );
1968  }
1969 
1970  flash.addEventListener('mouseOver', function(client) {
1971  if ( oConfig.fnMouseover !== null )
1972  {
1973  oConfig.fnMouseover.call( that, nButton, oConfig, flash );
1974  }
1975  } );
1976 
1977  flash.addEventListener('mouseOut', function(client) {
1978  if ( oConfig.fnMouseout !== null )
1979  {
1980  oConfig.fnMouseout.call( that, nButton, oConfig, flash );
1981  }
1982  } );
1983 
1984  flash.addEventListener('mouseDown', function(client) {
1985  if ( oConfig.fnClick !== null )
1986  {
1987  oConfig.fnClick.call( that, nButton, oConfig, flash );
1988  }
1989  } );
1990 
1991  flash.addEventListener('complete', function (client, text) {
1992  if ( oConfig.fnComplete !== null )
1993  {
1994  oConfig.fnComplete.call( that, nButton, oConfig, flash, text );
1995  }
1996  that._fnCollectionHide( nButton, oConfig );
1997  } );
1998 
1999  if ( oConfig.fnSelect !== null )
2000  {
2001  TableTools._fnEventListen( this, 'select', function (n) {
2002  oConfig.fnSelect.call( that, nButton, oConfig, n );
2003  } );
2004  }
2005 
2006  this._fnFlashGlue( flash, nButton, oConfig.sToolTip );
2007  },
2008 
2009 
2020  "_fnFlashGlue": function ( flash, node, text )
2021  {
2022  var that = this;
2023  var id = node.getAttribute('id');
2024 
2025  if ( document.getElementById(id) )
2026  {
2027  flash.glue( node, text );
2028  }
2029  else
2030  {
2031  setTimeout( function () {
2032  that._fnFlashGlue( flash, node, text );
2033  }, 100 );
2034  }
2035  },
2036 
2037 
2052  "_fnFlashSetText": function ( clip, sData )
2053  {
2054  var asData = this._fnChunkData( sData, 8192 );
2055 
2056  clip.clearText();
2057  for ( var i=0, iLen=asData.length ; i<iLen ; i++ )
2058  {
2059  clip.appendText( asData[i] );
2060  }
2061  },
2062 
2063 
2064 
2065  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2066  * Data retrieval functions
2067  */
2068 
2080  "_fnColumnTargets": function ( mColumns )
2081  {
2082  var aColumns = [];
2083  var dt = this.s.dt;
2084  var i, iLen;
2085  var columns = dt.aoColumns;
2086  var columnCount = columns.length;
2087 
2088  if ( typeof mColumns == "function" )
2089  {
2090  var a = mColumns.call( this, dt );
2091 
2092  for ( i=0, iLen=columnCount ; i<iLen ; i++ )
2093  {
2094  aColumns.push( $.inArray( i, a ) !== -1 ? true : false );
2095  }
2096  }
2097  else if ( typeof mColumns == "object" )
2098  {
2099  for ( i=0, iLen=columnCount ; i<iLen ; i++ )
2100  {
2101  aColumns.push( false );
2102  }
2103 
2104  for ( i=0, iLen=mColumns.length ; i<iLen ; i++ )
2105  {
2106  aColumns[ mColumns[i] ] = true;
2107  }
2108  }
2109  else if ( mColumns == "visible" )
2110  {
2111  for ( i=0, iLen=columnCount ; i<iLen ; i++ )
2112  {
2113  aColumns.push( columns[i].bVisible ? true : false );
2114  }
2115  }
2116  else if ( mColumns == "hidden" )
2117  {
2118  for ( i=0, iLen=columnCount ; i<iLen ; i++ )
2119  {
2120  aColumns.push( columns[i].bVisible ? false : true );
2121  }
2122  }
2123  else if ( mColumns == "sortable" )
2124  {
2125  for ( i=0, iLen=columnCount ; i<iLen ; i++ )
2126  {
2127  aColumns.push( columns[i].bSortable ? true : false );
2128  }
2129  }
2130  else /* all */
2131  {
2132  for ( i=0, iLen=columnCount ; i<iLen ; i++ )
2133  {
2134  aColumns.push( true );
2135  }
2136  }
2137 
2138  return aColumns;
2139  },
2140 
2141 
2148  "_fnNewline": function ( oConfig )
2149  {
2150  if ( oConfig.sNewLine == "auto" )
2151  {
2152  return navigator.userAgent.match(/Windows/) ? "\r\n" : "\n";
2153  }
2154  else
2155  {
2156  return oConfig.sNewLine;
2157  }
2158  },
2159 
2160 
2175  "_fnGetDataTablesData": function ( oConfig )
2176  {
2177  var i, iLen, j, jLen;
2178  var aRow, aData=[], sLoopData='', arr;
2179  var dt = this.s.dt, tr, child;
2180  var regex = new RegExp(oConfig.sFieldBoundary, "g"); /* Do it here for speed */
2181  var aColumnsInc = this._fnColumnTargets( oConfig.mColumns );
2182  var bSelectedOnly = (typeof oConfig.bSelectedOnly != 'undefined') ? oConfig.bSelectedOnly : false;
2183 
2184  /*
2185  * Header
2186  */
2187  if ( oConfig.bHeader )
2188  {
2189  aRow = [];
2190 
2191  for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
2192  {
2193  if ( aColumnsInc[i] )
2194  {
2195  sLoopData = dt.aoColumns[i].sTitle.replace(/\n/g," ").replace( /<.*?>/g, "" ).replace(/^\s+|\s+$/g,"");
2196  sLoopData = this._fnHtmlDecode( sLoopData );
2197 
2198  aRow.push( this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) );
2199  }
2200  }
2201 
2202  aData.push( aRow.join(oConfig.sFieldSeperator) );
2203  }
2204 
2205  bSelectedOnly = true;
2206 
2207  /*
2208  * Body
2209  */
2210  var aDataIndex;
2211  var aSelected = this.fnGetSelectedIndexes();
2212  bSelectedOnly = this.s.select.type !== "none" && bSelectedOnly && aSelected.length !== 0;
2213 
2214  if ( bSelectedOnly ) {
2215  // Use the selected indexes
2216  aDataIndex = aSelected;
2217  }
2218  else if ( DataTable.Api ) {
2219  // 1.10+ style
2220  aDataIndex = new DataTable.Api( dt )
2221  .rows( oConfig.oSelectorOpts )
2222  .indexes()
2223  .flatten()
2224  .toArray();
2225  }
2226  else {
2227  // 1.9- style
2228  aDataIndex = dt.oInstance
2229  .$('tr', oConfig.oSelectorOpts)
2230  .map( function (id, row) {
2231  return dt.oInstance.fnGetPosition( row );
2232  } )
2233  .get();
2234  }
2235 
2236  for ( j=0, jLen=aDataIndex.length ; j<jLen ; j++ )
2237  {
2238  tr = dt.aoData[ aDataIndex[j] ].nTr;
2239  aRow = [];
2240 
2241  /* Columns */
2242  for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
2243  {
2244  if ( aColumnsInc[i] )
2245  {
2246  /* Convert to strings (with small optimisation) */
2247  var mTypeData = dt.oApi._fnGetCellData( dt, aDataIndex[j], i, 'display' );
2248  if ( oConfig.fnCellRender )
2249  {
2250  sLoopData = oConfig.fnCellRender( mTypeData, i, tr, aDataIndex[j] )+"";
2251  }
2252  else if ( typeof mTypeData == "string" )
2253  {
2254  /* Strip newlines, replace img tags with alt attr. and finally strip html... */
2255  sLoopData = mTypeData.replace(/\n/g," ");
2256  sLoopData =
2257  sLoopData.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi,
2258  '$1$2$3');
2259  sLoopData = sLoopData.replace( /<.*?>/g, "" );
2260  }
2261  else
2262  {
2263  sLoopData = mTypeData+"";
2264  }
2265 
2266  /* Trim and clean the data */
2267  sLoopData = sLoopData.replace(/^\s+/, '').replace(/\s+$/, '');
2268  sLoopData = this._fnHtmlDecode( sLoopData );
2269 
2270  /* Bound it and add it to the total data */
2271  aRow.push( this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) );
2272  }
2273  }
2274 
2275  aData.push( aRow.join(oConfig.sFieldSeperator) );
2276 
2277  /* Details rows from fnOpen */
2278  if ( oConfig.bOpenRows )
2279  {
2280  arr = $.grep(dt.aoOpenRows, function(o) { return o.nParent === tr; });
2281 
2282  if ( arr.length === 1 )
2283  {
2284  sLoopData = this._fnBoundData( $('td', arr[0].nTr).html(), oConfig.sFieldBoundary, regex );
2285  aData.push( sLoopData );
2286  }
2287  }
2288  }
2289 
2290  /*
2291  * Footer
2292  */
2293  if ( oConfig.bFooter && dt.nTFoot !== null )
2294  {
2295  aRow = [];
2296 
2297  for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
2298  {
2299  if ( aColumnsInc[i] && dt.aoColumns[i].nTf !== null )
2300  {
2301  sLoopData = dt.aoColumns[i].nTf.innerHTML.replace(/\n/g," ").replace( /<.*?>/g, "" );
2302  sLoopData = this._fnHtmlDecode( sLoopData );
2303 
2304  aRow.push( this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) );
2305  }
2306  }
2307 
2308  aData.push( aRow.join(oConfig.sFieldSeperator) );
2309  }
2310 
2311  var _sLastData = aData.join( this._fnNewline(oConfig) );
2312  return _sLastData;
2313  },
2314 
2315 
2326  "_fnBoundData": function ( sData, sBoundary, regex )
2327  {
2328  if ( sBoundary === "" )
2329  {
2330  return sData;
2331  }
2332  else
2333  {
2334  return sBoundary + sData.replace(regex, sBoundary+sBoundary) + sBoundary;
2335  }
2336  },
2337 
2338 
2347  "_fnChunkData": function ( sData, iSize )
2348  {
2349  var asReturn = [];
2350  var iStrlen = sData.length;
2351 
2352  for ( var i=0 ; i<iStrlen ; i+=iSize )
2353  {
2354  if ( i+iSize < iStrlen )
2355  {
2356  asReturn.push( sData.substring( i, i+iSize ) );
2357  }
2358  else
2359  {
2360  asReturn.push( sData.substring( i, iStrlen ) );
2361  }
2362  }
2363 
2364  return asReturn;
2365  },
2366 
2367 
2375  "_fnHtmlDecode": function ( sData )
2376  {
2377  if ( sData.indexOf('&') === -1 )
2378  {
2379  return sData;
2380  }
2381 
2382  var n = document.createElement('div');
2383 
2384  return sData.replace( /&([^\s]*?);/g, function( match, match2 ) {
2385  if ( match.substr(1, 1) === '#' )
2386  {
2387  return String.fromCharCode( Number(match2.substr(1)) );
2388  }
2389  else
2390  {
2391  n.innerHTML = match;
2392  return n.childNodes[0].nodeValue;
2393  }
2394  } );
2395  },
2396 
2397 
2398 
2399  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2400  * Printing functions
2401  */
2402 
2411  "_fnPrintStart": function ( oConfig )
2412  {
2413  var that = this;
2414  var oSetDT = this.s.dt;
2415 
2416  /* Parse through the DOM hiding everything that isn't needed for the table */
2417  this._fnPrintHideNodes( oSetDT.nTable );
2418 
2419  /* Show the whole table */
2420  this.s.print.saveStart = oSetDT._iDisplayStart;
2421  this.s.print.saveLength = oSetDT._iDisplayLength;
2422 
2423  if ( oConfig.bShowAll )
2424  {
2425  oSetDT._iDisplayStart = 0;
2426  oSetDT._iDisplayLength = -1;
2427  if ( oSetDT.oApi._fnCalculateEnd ) {
2428  oSetDT.oApi._fnCalculateEnd( oSetDT );
2429  }
2430  oSetDT.oApi._fnDraw( oSetDT );
2431  }
2432 
2433  /* Adjust the display for scrolling which might be done by DataTables */
2434  if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" )
2435  {
2436  this._fnPrintScrollStart( oSetDT );
2437 
2438  // If the table redraws while in print view, the DataTables scrolling
2439  // setup would hide the header, so we need to readd it on draw
2440  $(this.s.dt.nTable).bind('draw.DTTT_Print', function () {
2441  that._fnPrintScrollStart( oSetDT );
2442  } );
2443  }
2444 
2445  /* Remove the other DataTables feature nodes - but leave the table! and info div */
2446  var anFeature = oSetDT.aanFeatures;
2447  for ( var cFeature in anFeature )
2448  {
2449  if ( cFeature != 'i' && cFeature != 't' && cFeature.length == 1 )
2450  {
2451  for ( var i=0, iLen=anFeature[cFeature].length ; i<iLen ; i++ )
2452  {
2453  this.dom.print.hidden.push( {
2454  "node": anFeature[cFeature][i],
2455  "display": "block"
2456  } );
2457  anFeature[cFeature][i].style.display = "none";
2458  }
2459  }
2460  }
2461 
2462  /* Print class can be used for styling */
2463  $(document.body).addClass( this.classes.print.body );
2464 
2465  /* Show information message to let the user know what is happening */
2466  if ( oConfig.sInfo !== "" )
2467  {
2468  this.fnInfo( oConfig.sInfo, 3000 );
2469  }
2470 
2471  /* Add a message at the top of the page */
2472  if ( oConfig.sMessage )
2473  {
2474  $('<div/>')
2475  .addClass( this.classes.print.message )
2476  .html( oConfig.sMessage )
2477  .prependTo( 'body' );
2478  }
2479 
2480  /* Cache the scrolling and the jump to the top of the page */
2481  this.s.print.saveScroll = $(window).scrollTop();
2482  window.scrollTo( 0, 0 );
2483 
2484  /* Bind a key event listener to the document for the escape key -
2485  * it is removed in the callback
2486  */
2487  $(document).bind( "keydown.DTTT", function(e) {
2488  /* Only interested in the escape key */
2489  if ( e.keyCode == 27 )
2490  {
2491  e.preventDefault();
2492  that._fnPrintEnd.call( that, e );
2493  }
2494  } );
2495  },
2496 
2497 
2505  "_fnPrintEnd": function ( e )
2506  {
2507  var that = this;
2508  var oSetDT = this.s.dt;
2509  var oSetPrint = this.s.print;
2510  var oDomPrint = this.dom.print;
2511 
2512  /* Show all hidden nodes */
2513  this._fnPrintShowNodes();
2514 
2515  /* Restore DataTables' scrolling */
2516  if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" )
2517  {
2518  $(this.s.dt.nTable).unbind('draw.DTTT_Print');
2519 
2520  this._fnPrintScrollEnd();
2521  }
2522 
2523  /* Restore the scroll */
2524  window.scrollTo( 0, oSetPrint.saveScroll );
2525 
2526  /* Drop the print message */
2527  $('div.'+this.classes.print.message).remove();
2528 
2529  /* Styling class */
2530  $(document.body).removeClass( this.classes.print.body );
2531 
2532  /* Restore the table length */
2533  oSetDT._iDisplayStart = oSetPrint.saveStart;
2534  oSetDT._iDisplayLength = oSetPrint.saveLength;
2535  if ( oSetDT.oApi._fnCalculateEnd ) {
2536  oSetDT.oApi._fnCalculateEnd( oSetDT );
2537  }
2538  oSetDT.oApi._fnDraw( oSetDT );
2539 
2540  $(document).unbind( "keydown.DTTT" );
2541  },
2542 
2543 
2549  "_fnPrintScrollStart": function ()
2550  {
2551  var
2552  oSetDT = this.s.dt,
2553  nScrollHeadInner = oSetDT.nScrollHead.getElementsByTagName('div')[0],
2554  nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
2555  nScrollBody = oSetDT.nTable.parentNode,
2556  nTheadSize, nTfootSize;
2557 
2558  /* Copy the header in the thead in the body table, this way we show one single table when
2559  * in print view. Note that this section of code is more or less verbatim from DT 1.7.0
2560  */
2561  nTheadSize = oSetDT.nTable.getElementsByTagName('thead');
2562  if ( nTheadSize.length > 0 )
2563  {
2564  oSetDT.nTable.removeChild( nTheadSize[0] );
2565  }
2566 
2567  if ( oSetDT.nTFoot !== null )
2568  {
2569  nTfootSize = oSetDT.nTable.getElementsByTagName('tfoot');
2570  if ( nTfootSize.length > 0 )
2571  {
2572  oSetDT.nTable.removeChild( nTfootSize[0] );
2573  }
2574  }
2575 
2576  nTheadSize = oSetDT.nTHead.cloneNode(true);
2577  oSetDT.nTable.insertBefore( nTheadSize, oSetDT.nTable.childNodes[0] );
2578 
2579  if ( oSetDT.nTFoot !== null )
2580  {
2581  nTfootSize = oSetDT.nTFoot.cloneNode(true);
2582  oSetDT.nTable.insertBefore( nTfootSize, oSetDT.nTable.childNodes[1] );
2583  }
2584 
2585  /* Now adjust the table's viewport so we can actually see it */
2586  if ( oSetDT.oScroll.sX !== "" )
2587  {
2588  oSetDT.nTable.style.width = $(oSetDT.nTable).outerWidth()+"px";
2589  nScrollBody.style.width = $(oSetDT.nTable).outerWidth()+"px";
2590  nScrollBody.style.overflow = "visible";
2591  }
2592 
2593  if ( oSetDT.oScroll.sY !== "" )
2594  {
2595  nScrollBody.style.height = $(oSetDT.nTable).outerHeight()+"px";
2596  nScrollBody.style.overflow = "visible";
2597  }
2598  },
2599 
2600 
2607  "_fnPrintScrollEnd": function ()
2608  {
2609  var
2610  oSetDT = this.s.dt,
2611  nScrollBody = oSetDT.nTable.parentNode;
2612 
2613  if ( oSetDT.oScroll.sX !== "" )
2614  {
2615  nScrollBody.style.width = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sX );
2616  nScrollBody.style.overflow = "auto";
2617  }
2618 
2619  if ( oSetDT.oScroll.sY !== "" )
2620  {
2621  nScrollBody.style.height = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sY );
2622  nScrollBody.style.overflow = "auto";
2623  }
2624  },
2625 
2626 
2633  "_fnPrintShowNodes": function ( )
2634  {
2635  var anHidden = this.dom.print.hidden;
2636 
2637  for ( var i=0, iLen=anHidden.length ; i<iLen ; i++ )
2638  {
2639  anHidden[i].node.style.display = anHidden[i].display;
2640  }
2641  anHidden.splice( 0, anHidden.length );
2642  },
2643 
2644 
2653  "_fnPrintHideNodes": function ( nNode )
2654  {
2655  var anHidden = this.dom.print.hidden;
2656 
2657  var nParent = nNode.parentNode;
2658  var nChildren = nParent.childNodes;
2659  for ( var i=0, iLen=nChildren.length ; i<iLen ; i++ )
2660  {
2661  if ( nChildren[i] != nNode && nChildren[i].nodeType == 1 )
2662  {
2663  /* If our node is shown (don't want to show nodes which were previously hidden) */
2664  var sDisplay = $(nChildren[i]).css("display");
2665  if ( sDisplay != "none" )
2666  {
2667  /* Cache the node and it's previous state so we can restore it */
2668  anHidden.push( {
2669  "node": nChildren[i],
2670  "display": sDisplay
2671  } );
2672  nChildren[i].style.display = "none";
2673  }
2674  }
2675  }
2676 
2677  if ( nParent.nodeName.toUpperCase() != "BODY" )
2678  {
2679  this._fnPrintHideNodes( nParent );
2680  }
2681  }
2682 };
2683 
2684 
2685 
2686 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2687  * Static variables
2688  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2689 
2698 TableTools._aInstances = [];
2699 
2700 
2707 TableTools._aListeners = [];
2708 
2709 
2710 
2711 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2712  * Static methods
2713  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2714 
2721 TableTools.fnGetMasters = function ()
2722 {
2723  var a = [];
2724  for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ )
2725  {
2726  if ( TableTools._aInstances[i].s.master )
2727  {
2728  a.push( TableTools._aInstances[i] );
2729  }
2730  }
2731  return a;
2732 };
2733 
2740 TableTools.fnGetInstance = function ( node )
2741 {
2742  if ( typeof node != 'object' )
2743  {
2744  node = document.getElementById(node);
2745  }
2746 
2747  for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ )
2748  {
2749  if ( TableTools._aInstances[i].s.master && TableTools._aInstances[i].dom.table == node )
2750  {
2751  return TableTools._aInstances[i];
2752  }
2753  }
2754  return null;
2755 };
2756 
2757 
2768 TableTools._fnEventListen = function ( that, type, fn )
2769 {
2770  TableTools._aListeners.push( {
2771  "that": that,
2772  "type": type,
2773  "fn": fn
2774  } );
2775 };
2776 
2777 
2790 TableTools._fnEventDispatch = function ( that, type, node, selected )
2791 {
2792  var listeners = TableTools._aListeners;
2793  for ( var i=0, iLen=listeners.length ; i<iLen ; i++ )
2794  {
2795  if ( that.dom.table == listeners[i].that.dom.table && listeners[i].type == type )
2796  {
2797  listeners[i].fn( node, selected );
2798  }
2799  }
2800 };
2801 
2802 
2803 
2804 
2805 
2806 
2807 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2808  * Constants
2809  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2810 
2811 
2812 
2813 TableTools.buttonBase = {
2814  // Button base
2815  "sAction": "text",
2816  "sTag": "default",
2817  "sLinerTag": "default",
2818  "sButtonClass": "DTTT_button_text",
2819  "sButtonText": "Button text",
2820  "sTitle": "",
2821  "sToolTip": "",
2822 
2823  // Common button specific options
2824  "sCharSet": "utf8",
2825  "bBomInc": false,
2826  "sFileName": "*.csv",
2827  "sFieldBoundary": "",
2828  "sFieldSeperator": "\t",
2829  "sNewLine": "auto",
2830  "mColumns": "all", /* "all", "visible", "hidden" or array of column integers */
2831  "bHeader": true,
2832  "bFooter": true,
2833  "bOpenRows": false,
2834  "bSelectedOnly": false,
2835  "oSelectorOpts": undefined, // See http://datatables.net/docs/DataTables/1.9.4/#$ for full options
2836 
2837  // Callbacks
2838  "fnMouseover": null,
2839  "fnMouseout": null,
2840  "fnClick": null,
2841  "fnSelect": null,
2842  "fnComplete": null,
2843  "fnInit": null,
2844  "fnCellRender": null
2845 };
2846 
2847 
2851 TableTools.BUTTONS = {
2852  "csv": $.extend( {}, TableTools.buttonBase, {
2853  "sAction": "flash_save",
2854  "sButtonClass": "DTTT_button_csv",
2855  "sButtonText": "CSV",
2856  "sFieldBoundary": '"',
2857  "sFieldSeperator": ",",
2858  "fnClick": function( nButton, oConfig, flash ) {
2859  this.fnSetText( flash, this.fnGetTableData(oConfig) );
2860  }
2861  } ),
2862 
2863  "xls": $.extend( {}, TableTools.buttonBase, {
2864  "sAction": "flash_save",
2865  "sCharSet": "utf16le",
2866  "bBomInc": true,
2867  "sButtonClass": "DTTT_button_xls",
2868  "sButtonText": "Excel",
2869  "fnClick": function( nButton, oConfig, flash ) {
2870  this.fnSetText( flash, this.fnGetTableData(oConfig) );
2871  }
2872  } ),
2873 
2874  "copy": $.extend( {}, TableTools.buttonBase, {
2875  "sAction": "flash_copy",
2876  "sButtonClass": "DTTT_button_copy",
2877  "sButtonText": "Copy",
2878  "fnClick": function( nButton, oConfig, flash ) {
2879  this.fnSetText( flash, this.fnGetTableData(oConfig) );
2880  },
2881  "fnComplete": function(nButton, oConfig, flash, text) {
2882  var lines = text.split('\n').length;
2883  if (oConfig.bHeader) lines--;
2884  if (this.s.dt.nTFoot !== null && oConfig.bFooter) lines--;
2885  var plural = (lines==1) ? "" : "s";
2886  this.fnInfo( '<h6>Table copied</h6>'+
2887  '<p>Copied '+lines+' row'+plural+' to the clipboard.</p>',
2888  1500
2889  );
2890  }
2891  } ),
2892 
2893  "pdf": $.extend( {}, TableTools.buttonBase, {
2894  "sAction": "flash_pdf",
2895  "sNewLine": "\n",
2896  "sFileName": "*.pdf",
2897  "sButtonClass": "DTTT_button_pdf",
2898  "sButtonText": "PDF",
2899  "sPdfOrientation": "portrait",
2900  "sPdfSize": "A4",
2901  "sPdfMessage": "",
2902  "fnClick": function( nButton, oConfig, flash ) {
2903  this.fnSetText( flash,
2904  "title:"+ this.fnGetTitle(oConfig) +"\n"+
2905  "message:"+ oConfig.sPdfMessage +"\n"+
2906  "colWidth:"+ this.fnCalcColRatios(oConfig) +"\n"+
2907  "orientation:"+ oConfig.sPdfOrientation +"\n"+
2908  "size:"+ oConfig.sPdfSize +"\n"+
2909  "--/TableToolsOpts--\n" +
2910  this.fnGetTableData(oConfig)
2911  );
2912  }
2913  } ),
2914 
2915  "print": $.extend( {}, TableTools.buttonBase, {
2916  "sInfo": "<h6>Print view</h6><p>Please use your browser's print function to "+
2917  "print this table. Press escape when finished.</p>",
2918  "sMessage": null,
2919  "bShowAll": true,
2920  "sToolTip": "View print view",
2921  "sButtonClass": "DTTT_button_print",
2922  "sButtonText": "Print",
2923  "fnClick": function ( nButton, oConfig ) {
2924  this.fnPrint( true, oConfig );
2925  }
2926  } ),
2927 
2928  "text": $.extend( {}, TableTools.buttonBase ),
2929 
2930  "select": $.extend( {}, TableTools.buttonBase, {
2931  "sButtonText": "Select button",
2932  "fnSelect": function( nButton, oConfig ) {
2933  if ( this.fnGetSelected().length !== 0 ) {
2934  $(nButton).removeClass( this.classes.buttons.disabled );
2935  } else {
2936  $(nButton).addClass( this.classes.buttons.disabled );
2937  }
2938  },
2939  "fnInit": function( nButton, oConfig ) {
2940  $(nButton).addClass( this.classes.buttons.disabled );
2941  }
2942  } ),
2943 
2944  "select_single": $.extend( {}, TableTools.buttonBase, {
2945  "sButtonText": "Select button",
2946  "fnSelect": function( nButton, oConfig ) {
2947  var iSelected = this.fnGetSelected().length;
2948  if ( iSelected == 1 ) {
2949  $(nButton).removeClass( this.classes.buttons.disabled );
2950  } else {
2951  $(nButton).addClass( this.classes.buttons.disabled );
2952  }
2953  },
2954  "fnInit": function( nButton, oConfig ) {
2955  $(nButton).addClass( this.classes.buttons.disabled );
2956  }
2957  } ),
2958 
2959  "select_all": $.extend( {}, TableTools.buttonBase, {
2960  "sButtonText": "Select all",
2961  "fnClick": function( nButton, oConfig ) {
2962  this.fnSelectAll();
2963  },
2964  "fnSelect": function( nButton, oConfig ) {
2965  if ( this.fnGetSelected().length == this.s.dt.fnRecordsDisplay() ) {
2966  $(nButton).addClass( this.classes.buttons.disabled );
2967  } else {
2968  $(nButton).removeClass( this.classes.buttons.disabled );
2969  }
2970  }
2971  } ),
2972 
2973  "select_none": $.extend( {}, TableTools.buttonBase, {
2974  "sButtonText": "Deselect all",
2975  "fnClick": function( nButton, oConfig ) {
2976  this.fnSelectNone();
2977  },
2978  "fnSelect": function( nButton, oConfig ) {
2979  if ( this.fnGetSelected().length !== 0 ) {
2980  $(nButton).removeClass( this.classes.buttons.disabled );
2981  } else {
2982  $(nButton).addClass( this.classes.buttons.disabled );
2983  }
2984  },
2985  "fnInit": function( nButton, oConfig ) {
2986  $(nButton).addClass( this.classes.buttons.disabled );
2987  }
2988  } ),
2989 
2990  "ajax": $.extend( {}, TableTools.buttonBase, {
2991  "sAjaxUrl": "/xhr.php",
2992  "sButtonText": "Ajax button",
2993  "fnClick": function( nButton, oConfig ) {
2994  var sData = this.fnGetTableData(oConfig);
2995  $.ajax( {
2996  "url": oConfig.sAjaxUrl,
2997  "data": [
2998  { "name": "tableData", "value": sData }
2999  ],
3000  "success": oConfig.fnAjaxComplete,
3001  "dataType": "json",
3002  "type": "POST",
3003  "cache": false,
3004  "error": function () {
3005  alert( "Error detected when sending table data to server" );
3006  }
3007  } );
3008  },
3009  "fnAjaxComplete": function( json ) {
3010  alert( 'Ajax complete' );
3011  }
3012  } ),
3013 
3014  "div": $.extend( {}, TableTools.buttonBase, {
3015  "sAction": "div",
3016  "sTag": "div",
3017  "sButtonClass": "DTTT_nonbutton",
3018  "sButtonText": "Text button"
3019  } ),
3020 
3021  "collection": $.extend( {}, TableTools.buttonBase, {
3022  "sAction": "collection",
3023  "sButtonClass": "DTTT_button_collection",
3024  "sButtonText": "Collection",
3025  "fnClick": function( nButton, oConfig ) {
3026  this._fnCollectionShow(nButton, oConfig);
3027  }
3028  } )
3029 };
3030 /*
3031  * on* callback parameters:
3032  * 1. node - button element
3033  * 2. object - configuration object for this button
3034  * 3. object - ZeroClipboard reference (flash button only)
3035  * 4. string - Returned string from Flash (flash button only - and only on 'complete')
3036  */
3037 
3038 // Alias to match the other plug-ins styling
3039 TableTools.buttons = TableTools.BUTTONS;
3040 
3041 
3047 TableTools.classes = {
3048  "container": "DTTT_container",
3049  "buttons": {
3050  "normal": "DTTT_button",
3051  "disabled": "DTTT_disabled"
3052  },
3053  "collection": {
3054  "container": "DTTT_collection",
3055  "background": "DTTT_collection_background",
3056  "buttons": {
3057  "normal": "DTTT_button",
3058  "disabled": "DTTT_disabled"
3059  }
3060  },
3061  "select": {
3062  "table": "DTTT_selectable",
3063  "row": "DTTT_selected selected"
3064  },
3065  "print": {
3066  "body": "DTTT_Print",
3067  "info": "DTTT_print_info",
3068  "message": "DTTT_PrintMessage"
3069  }
3070 };
3071 
3072 
3077 TableTools.classes_themeroller = {
3078  "container": "DTTT_container ui-buttonset ui-buttonset-multi",
3079  "buttons": {
3080  "normal": "DTTT_button ui-button ui-state-default"
3081  },
3082  "collection": {
3083  "container": "DTTT_collection ui-buttonset ui-buttonset-multi"
3084  }
3085 };
3086 
3087 
3091 TableTools.DEFAULTS = {
3092  "sSwfPath": "../swf/copy_csv_xls_pdf.swf",
3093  "sRowSelect": "none",
3094  "sRowSelector": "tr",
3095  "sSelectedClass": null,
3096  "fnPreRowSelect": null,
3097  "fnRowSelected": null,
3098  "fnRowDeselected": null,
3099  "aButtons": [ "copy", "csv", "xls", "pdf", "print" ],
3100  "oTags": {
3101  "container": "div",
3102  "button": "a", // We really want to use buttons here, but Firefox and IE ignore the
3103  // click on the Flash element in the button (but not mouse[in|out]).
3104  "liner": "span",
3105  "collection": {
3106  "container": "div",
3107  "button": "a",
3108  "liner": "span"
3109  }
3110  }
3111 };
3112 
3113 // Alias to match the other plug-ins
3114 TableTools.defaults = TableTools.DEFAULTS;
3115 
3116 
3123 TableTools.prototype.CLASS = "TableTools";
3124 
3125 
3132 TableTools.version = "2.2.4";
3133 
3134 
3135 
3136 // DataTables 1.10 API
3137 //
3138 // This will be extended in a big way in in TableTools 3 to provide API methods
3139 // such as rows().select() and rows.selected() etc, but for the moment the
3140 // tabletools() method simply returns the instance.
3141 
3142 if ( $.fn.dataTable.Api ) {
3143  $.fn.dataTable.Api.register( 'tabletools()', function () {
3144  var tt = null;
3145 
3146  if ( this.context.length > 0 ) {
3147  tt = TableTools.fnGetInstance( this.context[0].nTable );
3148  }
3149 
3150  return tt;
3151  } );
3152 }
3153 
3154 
3155 
3156 
3157 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3158  * Initialisation
3159  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3160 
3161 /*
3162  * Register a new feature with DataTables
3163  */
3164 if ( typeof $.fn.dataTable == "function" &&
3165  typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
3166  $.fn.dataTableExt.fnVersionCheck('1.9.0') )
3167 {
3168  $.fn.dataTableExt.aoFeatures.push( {
3169  "fnInit": function( oDTSettings ) {
3170  var init = oDTSettings.oInit;
3171  var opts = init ?
3172  init.tableTools || init.oTableTools || {} :
3173  {};
3174 
3175  return new TableTools( oDTSettings.oInstance, opts ).dom.container;
3176  },
3177  "cFeature": "T",
3178  "sFeature": "TableTools"
3179  } );
3180 }
3181 else
3182 {
3183  alert( "Warning: TableTools requires DataTables 1.9.0 or newer - www.datatables.net/download");
3184 }
3185 
3186 $.fn.DataTable.TableTools = TableTools;
3187 
3188 })(jQuery, window, document);
3189 
3190 /*
3191  * Register a new feature with DataTables
3192  */
3193 if ( typeof $.fn.dataTable == "function" &&
3194  typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
3195  $.fn.dataTableExt.fnVersionCheck('1.9.0') )
3196 {
3197  $.fn.dataTableExt.aoFeatures.push( {
3198  "fnInit": function( oDTSettings ) {
3199  var oOpts = typeof oDTSettings.oInit.oTableTools != 'undefined' ?
3200  oDTSettings.oInit.oTableTools : {};
3201 
3202  var oTT = new TableTools( oDTSettings.oInstance, oOpts );
3203  TableTools._aInstances.push( oTT );
3204 
3205  return oTT.dom.container;
3206  },
3207  "cFeature": "T",
3208  "sFeature": "TableTools"
3209  } );
3210 }
3211 else
3212 {
3213  alert( "Warning: TableTools 2 requires DataTables 1.9.0 or newer - www.datatables.net/download");
3214 }
3215 
3216 
3217 $.fn.dataTable.TableTools = TableTools;
3218 $.fn.DataTable.TableTools = TableTools;
3219 
3220 
3221 return TableTools;
3222 }; // /factory
3223 
3224 
3225 // Define as an AMD module if possible
3226 if ( typeof define === 'function' && define.amd ) {
3227  define( ['jquery', 'datatables'], factory );
3228 }
3229 else if ( typeof exports === 'object' ) {
3230  // Node/CommonJS
3231  factory( require('jquery'), require('datatables') );
3232 }
3233 else if ( jQuery && !jQuery.fn.dataTable.TableTools ) {
3234  // Otherwise simply initialise as normal, stopping multiple evaluation
3235  factory( jQuery, jQuery.fn.dataTable );
3236 }
3237 
3238 
3239 })(window, document);
3240