src/ztfy/myams/resources/js/ext/jquery-dataTables-tableTools.js
changeset 0 8a19e25e39e4
equal deleted inserted replaced
-1:000000000000 0:8a19e25e39e4
       
     1 /*! TableTools 2.2.0
       
     2  * 2009-2014 SpryMedia Ltd - datatables.net/license
       
     3  *
       
     4  * ZeroClipboard 1.0.4
       
     5  * Author: Joseph Huckaby - MIT licensed
       
     6  */
       
     7 
       
     8 /**
       
     9  * @summary     TableTools
       
    10  * @description Tools and buttons for DataTables
       
    11  * @version     2.2.0
       
    12  * @file        dataTables.tableTools.js
       
    13  * @author      SpryMedia Ltd (www.sprymedia.co.uk)
       
    14  * @contact     www.sprymedia.co.uk/contact
       
    15  * @copyright   Copyright 2009-2014 SpryMedia Ltd.
       
    16  *
       
    17  * This source file is free software, available under the following license:
       
    18  *   MIT license - http://datatables.net/license/mit
       
    19  *
       
    20  * This source file is distributed in the hope that it will be useful, but
       
    21  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
       
    22  * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
       
    23  *
       
    24  * For details please refer to: http://www.datatables.net
       
    25  */
       
    26 
       
    27 
       
    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 () {
       
    60 						this.style.display = 'none';
       
    61 					};
       
    62 					thingy.show = function () {
       
    63 						this.style.display = '';
       
    64 					};
       
    65 					thingy.addClass = function (name) {
       
    66 						this.removeClass(name);
       
    67 						this.className += ' ' + name;
       
    68 					};
       
    69 					thingy.removeClass = function (name) {
       
    70 						this.className = this.className.replace(new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
       
    71 					};
       
    72 					thingy.hasClass = function (name) {
       
    73 						return !!this.className.match(new RegExp("\\s*" + name + "\\s*"));
       
    74 					};
       
    75 				}
       
    76 				return thingy;
       
    77 			},
       
    78 
       
    79 			setMoviePath: function (path) {
       
    80 				// set path to ZeroClipboard.swf
       
    81 				this.moviePath = path;
       
    82 			},
       
    83 
       
    84 			dispatch: function (id, eventName, args) {
       
    85 				// receive event from flash movie, send to client
       
    86 				var client = this.clients[id];
       
    87 				if (client) {
       
    88 					client.receiveEvent(eventName, args);
       
    89 				}
       
    90 			},
       
    91 
       
    92 			register: function (id, client) {
       
    93 				// register new client to receive events
       
    94 				this.clients[id] = client;
       
    95 			},
       
    96 
       
    97 			getDOMObjectPosition: function (obj) {
       
    98 				// get absolute coordinates for dom element
       
    99 				var info = {
       
   100 					left: 0,
       
   101 					top: 0,
       
   102 					width: obj.width ? obj.width : obj.offsetWidth,
       
   103 					height: obj.height ? obj.height : obj.offsetHeight
       
   104 				};
       
   105 
       
   106 				if (obj.style.width !== "") {
       
   107 					info.width = obj.style.width.replace("px", "");
       
   108 				}
       
   109 
       
   110 				if (obj.style.height !== "") {
       
   111 					info.height = obj.style.height.replace("px", "");
       
   112 				}
       
   113 
       
   114 				while (obj) {
       
   115 					info.left += obj.offsetLeft;
       
   116 					info.top += obj.offsetTop;
       
   117 					obj = obj.offsetParent;
       
   118 				}
       
   119 
       
   120 				return info;
       
   121 			},
       
   122 
       
   123 			Client: function (elem) {
       
   124 				// constructor for new simple upload client
       
   125 				this.handlers = {};
       
   126 
       
   127 				// unique ID
       
   128 				this.id = ZeroClipboard_TableTools.nextId++;
       
   129 				this.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id;
       
   130 
       
   131 				// register client with singleton to receive flash events
       
   132 				ZeroClipboard_TableTools.register(this.id, this);
       
   133 
       
   134 				// create movie
       
   135 				if (elem) {
       
   136 					this.glue(elem);
       
   137 				}
       
   138 			}
       
   139 		};
       
   140 
       
   141 		ZeroClipboard_TableTools.Client.prototype = {
       
   142 
       
   143 			id: 0, // unique ID for us
       
   144 			ready: false, // whether movie is ready to receive events or not
       
   145 			movie: null, // reference to movie object
       
   146 			clipText: '', // text to copy to clipboard
       
   147 			fileName: '', // default file save name
       
   148 			action: 'copy', // action to perform
       
   149 			handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
       
   150 			cssEffects: true, // enable CSS mouse effects on dom container
       
   151 			handlers: null, // user event handlers
       
   152 			sized: false,
       
   153 
       
   154 			glue: function (elem, title) {
       
   155 				// glue to DOM element
       
   156 				// elem can be ID or actual DOM element object
       
   157 				this.domElement = ZeroClipboard_TableTools.$(elem);
       
   158 
       
   159 				// float just above object, or zIndex 99 if dom element isn't set
       
   160 				var zIndex = 99;
       
   161 				if (this.domElement.style.zIndex) {
       
   162 					zIndex = parseInt(this.domElement.style.zIndex, 10) + 1;
       
   163 				}
       
   164 
       
   165 				// find X/Y position of domElement
       
   166 				var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
       
   167 
       
   168 				// create floating DIV above element
       
   169 				this.div = document.createElement('div');
       
   170 				var style = this.div.style;
       
   171 				style.position = 'absolute';
       
   172 				style.left = '0px';
       
   173 				style.top = '0px';
       
   174 				style.width = (box.width) + 'px';
       
   175 				style.height = box.height + 'px';
       
   176 				style.zIndex = zIndex;
       
   177 
       
   178 				if (typeof title != "undefined" && title !== "") {
       
   179 					this.div.title = title;
       
   180 				}
       
   181 				if (box.width !== 0 && box.height !== 0) {
       
   182 					this.sized = true;
       
   183 				}
       
   184 
       
   185 				// style.backgroundColor = '#f00'; // debug
       
   186 				if (this.domElement) {
       
   187 					this.domElement.appendChild(this.div);
       
   188 					this.div.innerHTML = this.getHTML(box.width, box.height).replace(/&/g, '&');
       
   189 				}
       
   190 			},
       
   191 
       
   192 			positionElement: function () {
       
   193 				var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
       
   194 				var style = this.div.style;
       
   195 
       
   196 				style.position = 'absolute';
       
   197 				//style.left = (this.domElement.offsetLeft)+'px';
       
   198 				//style.top = this.domElement.offsetTop+'px';
       
   199 				style.width = box.width + 'px';
       
   200 				style.height = box.height + 'px';
       
   201 
       
   202 				if (box.width !== 0 && box.height !== 0) {
       
   203 					this.sized = true;
       
   204 				} else {
       
   205 					return;
       
   206 				}
       
   207 
       
   208 				var flash = this.div.childNodes[0];
       
   209 				flash.width = box.width;
       
   210 				flash.height = box.height;
       
   211 			},
       
   212 
       
   213 			getHTML: function (width, height) {
       
   214 				// return HTML for movie
       
   215 				var html = '';
       
   216 				var flashvars = 'id=' + this.id +
       
   217 					'&width=' + width +
       
   218 					'&height=' + height;
       
   219 
       
   220 				if (navigator.userAgent.match(/MSIE/)) {
       
   221 					// IE gets an OBJECT tag
       
   222 					var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
       
   223 					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>';
       
   224 				}
       
   225 				else {
       
   226 					// all other browsers get an EMBED tag
       
   227 					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" />';
       
   228 				}
       
   229 				return html;
       
   230 			},
       
   231 
       
   232 			hide: function () {
       
   233 				// temporarily hide floater offscreen
       
   234 				if (this.div) {
       
   235 					this.div.style.left = '-2000px';
       
   236 				}
       
   237 			},
       
   238 
       
   239 			show: function () {
       
   240 				// show ourselves after a call to hide()
       
   241 				this.reposition();
       
   242 			},
       
   243 
       
   244 			destroy: function () {
       
   245 				// destroy control and floater
       
   246 				if (this.domElement && this.div) {
       
   247 					this.hide();
       
   248 					this.div.innerHTML = '';
       
   249 
       
   250 					var body = document.getElementsByTagName('body')[0];
       
   251 					try {
       
   252 						body.removeChild(this.div);
       
   253 					} catch (e) {
       
   254 					}
       
   255 
       
   256 					this.domElement = null;
       
   257 					this.div = null;
       
   258 				}
       
   259 			},
       
   260 
       
   261 			reposition: function (elem) {
       
   262 				// reposition our floating div, optionally to new container
       
   263 				// warning: container CANNOT change size, only position
       
   264 				if (elem) {
       
   265 					this.domElement = ZeroClipboard_TableTools.$(elem);
       
   266 					if (!this.domElement) {
       
   267 						this.hide();
       
   268 					}
       
   269 				}
       
   270 
       
   271 				if (this.domElement && this.div) {
       
   272 					var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
       
   273 					var style = this.div.style;
       
   274 					style.left = '' + box.left + 'px';
       
   275 					style.top = '' + box.top + 'px';
       
   276 				}
       
   277 			},
       
   278 
       
   279 			clearText: function () {
       
   280 				// clear the text to be copy / saved
       
   281 				this.clipText = '';
       
   282 				if (this.ready) {
       
   283 					this.movie.clearText();
       
   284 				}
       
   285 			},
       
   286 
       
   287 			appendText: function (newText) {
       
   288 				// append text to that which is to be copied / saved
       
   289 				this.clipText += newText;
       
   290 				if (this.ready) {
       
   291 					this.movie.appendText(newText);
       
   292 				}
       
   293 			},
       
   294 
       
   295 			setText: function (newText) {
       
   296 				// set text to be copied to be copied / saved
       
   297 				this.clipText = newText;
       
   298 				if (this.ready) {
       
   299 					this.movie.setText(newText);
       
   300 				}
       
   301 			},
       
   302 
       
   303 			setCharSet: function (charSet) {
       
   304 				// set the character set (UTF16LE or UTF8)
       
   305 				this.charSet = charSet;
       
   306 				if (this.ready) {
       
   307 					this.movie.setCharSet(charSet);
       
   308 				}
       
   309 			},
       
   310 
       
   311 			setBomInc: function (bomInc) {
       
   312 				// set if the BOM should be included or not
       
   313 				this.incBom = bomInc;
       
   314 				if (this.ready) {
       
   315 					this.movie.setBomInc(bomInc);
       
   316 				}
       
   317 			},
       
   318 
       
   319 			setFileName: function (newText) {
       
   320 				// set the file name
       
   321 				this.fileName = newText;
       
   322 				if (this.ready) {
       
   323 					this.movie.setFileName(newText);
       
   324 				}
       
   325 			},
       
   326 
       
   327 			setAction: function (newText) {
       
   328 				// set action (save or copy)
       
   329 				this.action = newText;
       
   330 				if (this.ready) {
       
   331 					this.movie.setAction(newText);
       
   332 				}
       
   333 			},
       
   334 
       
   335 			addEventListener: function (eventName, func) {
       
   336 				// add user event listener for event
       
   337 				// event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
       
   338 				eventName = eventName.toString().toLowerCase().replace(/^on/, '');
       
   339 				if (!this.handlers[eventName]) {
       
   340 					this.handlers[eventName] = [];
       
   341 				}
       
   342 				this.handlers[eventName].push(func);
       
   343 			},
       
   344 
       
   345 			setHandCursor: function (enabled) {
       
   346 				// enable hand cursor (true), or default arrow cursor (false)
       
   347 				this.handCursorEnabled = enabled;
       
   348 				if (this.ready) {
       
   349 					this.movie.setHandCursor(enabled);
       
   350 				}
       
   351 			},
       
   352 
       
   353 			setCSSEffects: function (enabled) {
       
   354 				// enable or disable CSS effects on DOM container
       
   355 				this.cssEffects = !!enabled;
       
   356 			},
       
   357 
       
   358 			receiveEvent: function (eventName, args) {
       
   359 				var self;
       
   360 
       
   361 				// receive event from flash
       
   362 				eventName = eventName.toString().toLowerCase().replace(/^on/, '');
       
   363 
       
   364 				// special behavior for certain events
       
   365 				switch (eventName) {
       
   366 					case 'load':
       
   367 						// movie claims it is ready, but in IE this isn't always the case...
       
   368 						// bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
       
   369 						this.movie = document.getElementById(this.movieId);
       
   370 						if (!this.movie) {
       
   371 							self = this;
       
   372 							setTimeout(function () {
       
   373 								self.receiveEvent('load', null);
       
   374 							}, 1);
       
   375 							return;
       
   376 						}
       
   377 
       
   378 						// firefox on pc needs a "kick" in order to set these in certain cases
       
   379 						if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
       
   380 							self = this;
       
   381 							setTimeout(function () {
       
   382 								self.receiveEvent('load', null);
       
   383 							}, 100);
       
   384 							this.ready = true;
       
   385 							return;
       
   386 						}
       
   387 
       
   388 						this.ready = true;
       
   389 						this.movie.clearText();
       
   390 						this.movie.appendText(this.clipText);
       
   391 						this.movie.setFileName(this.fileName);
       
   392 						this.movie.setAction(this.action);
       
   393 						this.movie.setCharSet(this.charSet);
       
   394 						this.movie.setBomInc(this.incBom);
       
   395 						this.movie.setHandCursor(this.handCursorEnabled);
       
   396 						break;
       
   397 
       
   398 					case 'mouseover':
       
   399 						if (this.domElement && this.cssEffects) {
       
   400 							//this.domElement.addClass('hover');
       
   401 							if (this.recoverActive) {
       
   402 								this.domElement.addClass('active');
       
   403 							}
       
   404 						}
       
   405 						break;
       
   406 
       
   407 					case 'mouseout':
       
   408 						if (this.domElement && this.cssEffects) {
       
   409 							this.recoverActive = false;
       
   410 							if (this.domElement.hasClass('active')) {
       
   411 								this.domElement.removeClass('active');
       
   412 								this.recoverActive = true;
       
   413 							}
       
   414 							//this.domElement.removeClass('hover');
       
   415 						}
       
   416 						break;
       
   417 
       
   418 					case 'mousedown':
       
   419 						if (this.domElement && this.cssEffects) {
       
   420 							this.domElement.addClass('active');
       
   421 						}
       
   422 						break;
       
   423 
       
   424 					case 'mouseup':
       
   425 						if (this.domElement && this.cssEffects) {
       
   426 							this.domElement.removeClass('active');
       
   427 							this.recoverActive = false;
       
   428 						}
       
   429 						break;
       
   430 				} // switch eventName
       
   431 
       
   432 				if (this.handlers[eventName]) {
       
   433 					for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
       
   434 						var func = this.handlers[eventName][idx];
       
   435 
       
   436 						if (typeof(func) == 'function') {
       
   437 							// actual function reference
       
   438 							func(this, args);
       
   439 						}
       
   440 						else if ((typeof(func) == 'object') && (func.length == 2)) {
       
   441 							// PHP style object + method, i.e. [myObject, 'myMethod']
       
   442 							func[0][ func[1] ](this, args);
       
   443 						}
       
   444 						else if (typeof(func) == 'string') {
       
   445 							// name of function
       
   446 							window[func](this, args);
       
   447 						}
       
   448 					} // foreach event handler defined
       
   449 				} // user defined handler for event
       
   450 			}
       
   451 
       
   452 		};
       
   453 
       
   454 // For the Flash binding to work, ZeroClipboard_TableTools must be on the global
       
   455 // object list
       
   456 		window.ZeroClipboard_TableTools = ZeroClipboard_TableTools;
       
   457 //include TableTools.js
       
   458 		/* TableTools
       
   459 		 * 2009-2014 SpryMedia Ltd - datatables.net/license
       
   460 		 */
       
   461 
       
   462 		/*globals ZeroClipboard_TableTools*/
       
   463 
       
   464 		/* Global scope for TableTools */
       
   465 		var TableTools;
       
   466 
       
   467 		(function ($, window, document) {
       
   468 
       
   469 			/**
       
   470 			 * TableTools provides flexible buttons and other tools for a DataTables enhanced table
       
   471 			 * @class TableTools
       
   472 			 * @constructor
       
   473 			 * @param {Object} oDT DataTables instance. When using DataTables 1.10 this can
       
   474 			 *   also be a jQuery collection, jQuery selector, table node, DataTables API
       
   475 			 *   instance or DataTables settings object.
       
   476 			 * @param {Object} oOpts TableTools options
       
   477 			 * @param {String} oOpts.sSwfPath ZeroClipboard SWF path
       
   478 			 * @param {String} oOpts.sRowSelect Row selection options - 'none', 'single', 'multi' or 'os'
       
   479 			 * @param {Function} oOpts.fnPreRowSelect Callback function just prior to row selection
       
   480 			 * @param {Function} oOpts.fnRowSelected Callback function just after row selection
       
   481 			 * @param {Function} oOpts.fnRowDeselected Callback function when row is deselected
       
   482 			 * @param {Array} oOpts.aButtons List of buttons to be used
       
   483 			 */
       
   484 			TableTools = function (oDT, oOpts) {
       
   485 				/* Santiy check that we are a new instance */
       
   486 				if (!this instanceof TableTools) {
       
   487 					alert("Warning: TableTools must be initialised with the keyword 'new'");
       
   488 				}
       
   489 
       
   490 				// In 1.10 we can use the API to get the settings object from a number of
       
   491 				// sources
       
   492 				var dtSettings = $.fn.dataTable.Api ?
       
   493 					new $.fn.dataTable.Api(oDT).settings()[0] :
       
   494 					oDT.fnSettings();
       
   495 
       
   496 
       
   497 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
   498 				 * Public class variables
       
   499 				 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
   500 
       
   501 				/**
       
   502 				 * @namespace Settings object which contains customisable information for TableTools instance
       
   503 				 */
       
   504 				this.s = {
       
   505 					/**
       
   506 					 * Store 'this' so the instance can be retrieved from the settings object
       
   507 					 * @property that
       
   508 					 * @type     object
       
   509 					 * @default  this
       
   510 					 */
       
   511 					"that": this,
       
   512 
       
   513 					/**
       
   514 					 * DataTables settings objects
       
   515 					 * @property dt
       
   516 					 * @type     object
       
   517 					 * @default  <i>From the oDT init option</i>
       
   518 					 */
       
   519 					"dt": dtSettings,
       
   520 
       
   521 					/**
       
   522 					 * @namespace Print specific information
       
   523 					 */
       
   524 					"print": {
       
   525 						/**
       
   526 						 * DataTables draw 'start' point before the printing display was shown
       
   527 						 *  @property saveStart
       
   528 						 *  @type     int
       
   529 						 *  @default  -1
       
   530 						 */
       
   531 						"saveStart": -1,
       
   532 
       
   533 						/**
       
   534 						 * DataTables draw 'length' point before the printing display was shown
       
   535 						 *  @property saveLength
       
   536 						 *  @type     int
       
   537 						 *  @default  -1
       
   538 						 */
       
   539 						"saveLength": -1,
       
   540 
       
   541 						/**
       
   542 						 * Page scrolling point before the printing display was shown so it can be restored
       
   543 						 *  @property saveScroll
       
   544 						 *  @type     int
       
   545 						 *  @default  -1
       
   546 						 */
       
   547 						"saveScroll": -1,
       
   548 
       
   549 						/**
       
   550 						 * Wrapped function to end the print display (to maintain scope)
       
   551 						 *  @property funcEnd
       
   552 						 *  @type     Function
       
   553 						 *  @default  function () {}
       
   554 						 */
       
   555 						"funcEnd": function () {
       
   556 						}
       
   557 					},
       
   558 
       
   559 					/**
       
   560 					 * A unique ID is assigned to each button in each instance
       
   561 					 * @property buttonCounter
       
   562 					 *  @type     int
       
   563 					 * @default  0
       
   564 					 */
       
   565 					"buttonCounter": 0,
       
   566 
       
   567 					/**
       
   568 					 * @namespace Select rows specific information
       
   569 					 */
       
   570 					"select": {
       
   571 						/**
       
   572 						 * Select type - can be 'none', 'single' or 'multi'
       
   573 						 * @property type
       
   574 						 *  @type     string
       
   575 						 * @default  ""
       
   576 						 */
       
   577 						"type": "",
       
   578 
       
   579 						/**
       
   580 						 * Array of nodes which are currently selected
       
   581 						 *  @property selected
       
   582 						 *  @type     array
       
   583 						 *  @default  []
       
   584 						 */
       
   585 						"selected": [],
       
   586 
       
   587 						/**
       
   588 						 * Function to run before the selection can take place. Will cancel the select if the
       
   589 						 * function returns false
       
   590 						 *  @property preRowSelect
       
   591 						 *  @type     Function
       
   592 						 *  @default  null
       
   593 						 */
       
   594 						"preRowSelect": null,
       
   595 
       
   596 						/**
       
   597 						 * Function to run when a row is selected
       
   598 						 *  @property postSelected
       
   599 						 *  @type     Function
       
   600 						 *  @default  null
       
   601 						 */
       
   602 						"postSelected": null,
       
   603 
       
   604 						/**
       
   605 						 * Function to run when a row is deselected
       
   606 						 *  @property postDeselected
       
   607 						 *  @type     Function
       
   608 						 *  @default  null
       
   609 						 */
       
   610 						"postDeselected": null,
       
   611 
       
   612 						/**
       
   613 						 * Indicate if all rows are selected (needed for server-side processing)
       
   614 						 *  @property all
       
   615 						 *  @type     boolean
       
   616 						 *  @default  false
       
   617 						 */
       
   618 						"all": false,
       
   619 
       
   620 						/**
       
   621 						 * Class name to add to selected TR nodes
       
   622 						 *  @property selectedClass
       
   623 						 *  @type     String
       
   624 						 *  @default  ""
       
   625 						 */
       
   626 						"selectedClass": ""
       
   627 					},
       
   628 
       
   629 					/**
       
   630 					 * Store of the user input customisation object
       
   631 					 *  @property custom
       
   632 					 *  @type     object
       
   633 					 *  @default  {}
       
   634 					 */
       
   635 					"custom": {},
       
   636 
       
   637 					/**
       
   638 					 * SWF movie path
       
   639 					 *  @property swfPath
       
   640 					 *  @type     string
       
   641 					 *  @default  ""
       
   642 					 */
       
   643 					"swfPath": "",
       
   644 
       
   645 					/**
       
   646 					 * Default button set
       
   647 					 *  @property buttonSet
       
   648 					 *  @type     array
       
   649 					 *  @default  []
       
   650 					 */
       
   651 					"buttonSet": [],
       
   652 
       
   653 					/**
       
   654 					 * When there is more than one TableTools instance for a DataTable, there must be a
       
   655 					 * master which controls events (row selection etc)
       
   656 					 *  @property master
       
   657 					 *  @type     boolean
       
   658 					 *  @default  false
       
   659 					 */
       
   660 					"master": false,
       
   661 
       
   662 					/**
       
   663 					 * Tag names that are used for creating collections and buttons
       
   664 					 *  @namesapce
       
   665 					 */
       
   666 					"tags": {}
       
   667 				};
       
   668 
       
   669 
       
   670 				/**
       
   671 				 * @namespace Common and useful DOM elements for the class instance
       
   672 				 */
       
   673 				this.dom = {
       
   674 					/**
       
   675 					 * DIV element that is create and all TableTools buttons (and their children) put into
       
   676 					 *  @property container
       
   677 					 *  @type     node
       
   678 					 *  @default  null
       
   679 					 */
       
   680 					"container": null,
       
   681 
       
   682 					/**
       
   683 					 * The table node to which TableTools will be applied
       
   684 					 *  @property table
       
   685 					 *  @type     node
       
   686 					 *  @default  null
       
   687 					 */
       
   688 					"table": null,
       
   689 
       
   690 					/**
       
   691 					 * @namespace Nodes used for the print display
       
   692 					 */
       
   693 					"print": {
       
   694 						/**
       
   695 						 * Nodes which have been removed from the display by setting them to display none
       
   696 						 *  @property hidden
       
   697 						 *  @type     array
       
   698 						 *  @default  []
       
   699 						 */
       
   700 						"hidden": [],
       
   701 
       
   702 						/**
       
   703 						 * The information display saying telling the user about the print display
       
   704 						 *  @property message
       
   705 						 *  @type     node
       
   706 						 *  @default  null
       
   707 						 */
       
   708 						"message": null
       
   709 					},
       
   710 
       
   711 					/**
       
   712 					 * @namespace Nodes used for a collection display. This contains the currently used collection
       
   713 					 */
       
   714 					"collection": {
       
   715 						/**
       
   716 						 * The div wrapper containing the buttons in the collection (i.e. the menu)
       
   717 						 *  @property collection
       
   718 						 *  @type     node
       
   719 						 *  @default  null
       
   720 						 */
       
   721 						"collection": null,
       
   722 
       
   723 						/**
       
   724 						 * Background display to provide focus and capture events
       
   725 						 *  @property background
       
   726 						 *  @type     node
       
   727 						 *  @default  null
       
   728 						 */
       
   729 						"background": null
       
   730 					}
       
   731 				};
       
   732 
       
   733 				/**
       
   734 				 * @namespace Name space for the classes that this TableTools instance will use
       
   735 				 * @extends TableTools.classes
       
   736 				 */
       
   737 				this.classes = $.extend(true, {}, TableTools.classes);
       
   738 				if (this.s.dt.bJUI) {
       
   739 					$.extend(true, this.classes, TableTools.classes_themeroller);
       
   740 				}
       
   741 
       
   742 
       
   743 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
   744 				 * Public class methods
       
   745 				 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
   746 
       
   747 				/**
       
   748 				 * Retreieve the settings object from an instance
       
   749 				 *  @method fnSettings
       
   750 				 *  @returns {object} TableTools settings object
       
   751 				 */
       
   752 				this.fnSettings = function () {
       
   753 					return this.s;
       
   754 				};
       
   755 
       
   756 
       
   757 				/* Constructor logic */
       
   758 				if (typeof oOpts == 'undefined') {
       
   759 					oOpts = {};
       
   760 				}
       
   761 
       
   762 				this._fnConstruct(oOpts);
       
   763 
       
   764 				return this;
       
   765 			};
       
   766 
       
   767 
       
   768 			TableTools.prototype = {
       
   769 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
   770 				 * Public methods
       
   771 				 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
   772 
       
   773 				/**
       
   774 				 * Retreieve the settings object from an instance
       
   775 				 *  @returns {array} List of TR nodes which are currently selected
       
   776 				 *  @param {boolean} [filtered=false] Get only selected rows which are
       
   777 				 *    available given the filtering applied to the table. By default
       
   778 				 *    this is false -  i.e. all rows, regardless of filtering are
       
   779 				 selected.
       
   780 				 */
       
   781 				"fnGetSelected": function (filtered) {
       
   782 					var
       
   783 						out = [],
       
   784 						data = this.s.dt.aoData,
       
   785 						displayed = this.s.dt.aiDisplay,
       
   786 						i, iLen;
       
   787 
       
   788 					if (filtered) {
       
   789 						// Only consider filtered rows
       
   790 						for (i = 0, iLen = displayed.length; i < iLen; i++) {
       
   791 							if (data[ displayed[i] ]._DTTT_selected) {
       
   792 								out.push(data[ displayed[i] ].nTr);
       
   793 							}
       
   794 						}
       
   795 					}
       
   796 					else {
       
   797 						// Use all rows
       
   798 						for (i = 0, iLen = data.length; i < iLen; i++) {
       
   799 							if (data[i]._DTTT_selected) {
       
   800 								out.push(data[i].nTr);
       
   801 							}
       
   802 						}
       
   803 					}
       
   804 
       
   805 					return out;
       
   806 				},
       
   807 
       
   808 
       
   809 				/**
       
   810 				 * Get the data source objects/arrays from DataTables for the selected rows (same as
       
   811 				 * fnGetSelected followed by fnGetData on each row from the table)
       
   812 				 *  @returns {array} Data from the TR nodes which are currently selected
       
   813 				 */
       
   814 				"fnGetSelectedData": function () {
       
   815 					var out = [];
       
   816 					var data = this.s.dt.aoData;
       
   817 					var i, iLen;
       
   818 
       
   819 					for (i = 0, iLen = data.length; i < iLen; i++) {
       
   820 						if (data[i]._DTTT_selected) {
       
   821 							out.push(this.s.dt.oInstance.fnGetData(i));
       
   822 						}
       
   823 					}
       
   824 
       
   825 					return out;
       
   826 				},
       
   827 
       
   828 
       
   829 				/**
       
   830 				 * Check to see if a current row is selected or not
       
   831 				 *  @param {Node} n TR node to check if it is currently selected or not
       
   832 				 *  @returns {Boolean} true if select, false otherwise
       
   833 				 */
       
   834 				"fnIsSelected": function (n) {
       
   835 					var pos = this.s.dt.oInstance.fnGetPosition(n);
       
   836 					return (this.s.dt.aoData[pos]._DTTT_selected === true) ? true : false;
       
   837 				},
       
   838 
       
   839 
       
   840 				/**
       
   841 				 * Select all rows in the table
       
   842 				 *  @param {boolean} [filtered=false] Select only rows which are available
       
   843 				 *    given the filtering applied to the table. By default this is false -
       
   844 				 *    i.e. all rows, regardless of filtering are selected.
       
   845 				 */
       
   846 				"fnSelectAll": function (filtered) {
       
   847 					var s = this._fnGetMasterSettings();
       
   848 
       
   849 					this._fnRowSelect((filtered === true) ?
       
   850 										  s.dt.aiDisplay :
       
   851 										  s.dt.aoData
       
   852 					);
       
   853 				},
       
   854 
       
   855 
       
   856 				/**
       
   857 				 * Deselect all rows in the table
       
   858 				 *  @param {boolean} [filtered=false] Deselect only rows which are available
       
   859 				 *    given the filtering applied to the table. By default this is false -
       
   860 				 *    i.e. all rows, regardless of filtering are deselected.
       
   861 				 */
       
   862 				"fnSelectNone": function (filtered) {
       
   863 					var s = this._fnGetMasterSettings();
       
   864 
       
   865 					this._fnRowDeselect(this.fnGetSelected(filtered));
       
   866 				},
       
   867 
       
   868 
       
   869 				/**
       
   870 				 * Select row(s)
       
   871 				 *  @param {node|object|array} n The row(s) to select. Can be a single DOM
       
   872 				 *    TR node, an array of TR nodes or a jQuery object.
       
   873 				 */
       
   874 				"fnSelect": function (n) {
       
   875 					if (this.s.select.type == "single") {
       
   876 						this.fnSelectNone();
       
   877 						this._fnRowSelect(n);
       
   878 					}
       
   879 					else if (this.s.select.type == "multi") {
       
   880 						this._fnRowSelect(n);
       
   881 					}
       
   882 				},
       
   883 
       
   884 
       
   885 				/**
       
   886 				 * Deselect row(s)
       
   887 				 *  @param {node|object|array} n The row(s) to deselect. Can be a single DOM
       
   888 				 *    TR node, an array of TR nodes or a jQuery object.
       
   889 				 */
       
   890 				"fnDeselect": function (n) {
       
   891 					this._fnRowDeselect(n);
       
   892 				},
       
   893 
       
   894 
       
   895 				/**
       
   896 				 * Get the title of the document - useful for file names. The title is retrieved from either
       
   897 				 * the configuration object's 'title' parameter, or the HTML document title
       
   898 				 *  @param   {Object} oConfig Button configuration object
       
   899 				 *  @returns {String} Button title
       
   900 				 */
       
   901 				"fnGetTitle": function (oConfig) {
       
   902 					var sTitle = "";
       
   903 					if (typeof oConfig.sTitle != 'undefined' && oConfig.sTitle !== "") {
       
   904 						sTitle = oConfig.sTitle;
       
   905 					} else {
       
   906 						var anTitle = document.getElementsByTagName('title');
       
   907 						if (anTitle.length > 0) {
       
   908 							sTitle = anTitle[0].innerHTML;
       
   909 						}
       
   910 					}
       
   911 
       
   912 					/* Strip characters which the OS will object to - checking for UTF8 support in the scripting
       
   913 					 * engine
       
   914 					 */
       
   915 					if ("\u00A1".toString().length < 4) {
       
   916 						return sTitle.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
       
   917 					} else {
       
   918 						return sTitle.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g, "");
       
   919 					}
       
   920 				},
       
   921 
       
   922 
       
   923 				/**
       
   924 				 * Calculate a unity array with the column width by proportion for a set of columns to be
       
   925 				 * included for a button. This is particularly useful for PDF creation, where we can use the
       
   926 				 * column widths calculated by the browser to size the columns in the PDF.
       
   927 				 *  @param   {Object} oConfig Button configuration object
       
   928 				 *  @returns {Array} Unity array of column ratios
       
   929 				 */
       
   930 				"fnCalcColRatios": function (oConfig) {
       
   931 					var
       
   932 						aoCols = this.s.dt.aoColumns,
       
   933 						aColumnsInc = this._fnColumnTargets(oConfig.mColumns),
       
   934 						aColWidths = [],
       
   935 						iWidth = 0, iTotal = 0, i, iLen;
       
   936 
       
   937 					for (i = 0, iLen = aColumnsInc.length; i < iLen; i++) {
       
   938 						if (aColumnsInc[i]) {
       
   939 							iWidth = aoCols[i].nTh.offsetWidth;
       
   940 							iTotal += iWidth;
       
   941 							aColWidths.push(iWidth);
       
   942 						}
       
   943 					}
       
   944 
       
   945 					for (i = 0, iLen = aColWidths.length; i < iLen; i++) {
       
   946 						aColWidths[i] = aColWidths[i] / iTotal;
       
   947 					}
       
   948 
       
   949 					return aColWidths.join('\t');
       
   950 				},
       
   951 
       
   952 
       
   953 				/**
       
   954 				 * Get the information contained in a table as a string
       
   955 				 *  @param   {Object} oConfig Button configuration object
       
   956 				 *  @returns {String} Table data as a string
       
   957 				 */
       
   958 				"fnGetTableData": function (oConfig) {
       
   959 					/* In future this could be used to get data from a plain HTML source as well as DataTables */
       
   960 					if (this.s.dt) {
       
   961 						return this._fnGetDataTablesData(oConfig);
       
   962 					}
       
   963 				},
       
   964 
       
   965 
       
   966 				/**
       
   967 				 * Pass text to a flash button instance, which will be used on the button's click handler
       
   968 				 *  @param   {Object} clip Flash button object
       
   969 				 *  @param   {String} text Text to set
       
   970 				 */
       
   971 				"fnSetText": function (clip, text) {
       
   972 					this._fnFlashSetText(clip, text);
       
   973 				},
       
   974 
       
   975 
       
   976 				/**
       
   977 				 * Resize the flash elements of the buttons attached to this TableTools instance - this is
       
   978 				 * useful for when initialising TableTools when it is hidden (display:none) since sizes can't
       
   979 				 * be calculated at that time.
       
   980 				 */
       
   981 				"fnResizeButtons": function () {
       
   982 					for (var cli in ZeroClipboard_TableTools.clients) {
       
   983 						if (cli) {
       
   984 							var client = ZeroClipboard_TableTools.clients[cli];
       
   985 							if (typeof client.domElement != 'undefined' &&
       
   986 								client.domElement.parentNode) {
       
   987 								client.positionElement();
       
   988 							}
       
   989 						}
       
   990 					}
       
   991 				},
       
   992 
       
   993 
       
   994 				/**
       
   995 				 * Check to see if any of the ZeroClipboard client's attached need to be resized
       
   996 				 */
       
   997 				"fnResizeRequired": function () {
       
   998 					for (var cli in ZeroClipboard_TableTools.clients) {
       
   999 						if (cli) {
       
  1000 							var client = ZeroClipboard_TableTools.clients[cli];
       
  1001 							if (typeof client.domElement != 'undefined' &&
       
  1002 								client.domElement.parentNode == this.dom.container &&
       
  1003 								client.sized === false) {
       
  1004 								return true;
       
  1005 							}
       
  1006 						}
       
  1007 					}
       
  1008 					return false;
       
  1009 				},
       
  1010 
       
  1011 
       
  1012 				/**
       
  1013 				 * Programmatically enable or disable the print view
       
  1014 				 *  @param {boolean} [bView=true] Show the print view if true or not given. If false, then
       
  1015 				 *    terminate the print view and return to normal.
       
  1016 				 *  @param {object} [oConfig={}] Configuration for the print view
       
  1017 				 *  @param {boolean} [oConfig.bShowAll=false] Show all rows in the table if true
       
  1018 				 *  @param {string} [oConfig.sInfo] Information message, displayed as an overlay to the
       
  1019 				 *    user to let them know what the print view is.
       
  1020 				 *  @param {string} [oConfig.sMessage] HTML string to show at the top of the document - will
       
  1021 				 *    be included in the printed document.
       
  1022 				 */
       
  1023 				"fnPrint": function (bView, oConfig) {
       
  1024 					if (oConfig === undefined) {
       
  1025 						oConfig = {};
       
  1026 					}
       
  1027 
       
  1028 					if (bView === undefined || bView) {
       
  1029 						this._fnPrintStart(oConfig);
       
  1030 					}
       
  1031 					else {
       
  1032 						this._fnPrintEnd();
       
  1033 					}
       
  1034 				},
       
  1035 
       
  1036 
       
  1037 				/**
       
  1038 				 * Show a message to the end user which is nicely styled
       
  1039 				 *  @param {string} message The HTML string to show to the user
       
  1040 				 *  @param {int} time The duration the message is to be shown on screen for (mS)
       
  1041 				 */
       
  1042 				"fnInfo": function (message, time) {
       
  1043 					var info = $('<div/>')
       
  1044 						.addClass(this.classes.print.info)
       
  1045 						.html(message)
       
  1046 						.appendTo('body');
       
  1047 
       
  1048 					setTimeout(function () {
       
  1049 						info.fadeOut("normal", function () {
       
  1050 							info.remove();
       
  1051 						});
       
  1052 					}, time);
       
  1053 				},
       
  1054 
       
  1055 
       
  1056 				/**
       
  1057 				 * Get the container element of the instance for attaching to the DOM
       
  1058 				 *   @returns {node} DOM node
       
  1059 				 */
       
  1060 				"fnContainer": function () {
       
  1061 					return this.dom.container;
       
  1062 				},
       
  1063 
       
  1064 
       
  1065 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1066 				 * Private methods (they are of course public in JS, but recommended as private)
       
  1067 				 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  1068 
       
  1069 				/**
       
  1070 				 * Constructor logic
       
  1071 				 *  @method  _fnConstruct
       
  1072 				 *  @param   {Object} oOpts Same as TableTools constructor
       
  1073 				 *  @returns void
       
  1074 				 *  @private
       
  1075 				 */
       
  1076 				"_fnConstruct": function (oOpts) {
       
  1077 					var that = this;
       
  1078 
       
  1079 					this._fnCustomiseSettings(oOpts);
       
  1080 
       
  1081 					/* Container element */
       
  1082 					this.dom.container = document.createElement(this.s.tags.container);
       
  1083 					this.dom.container.className = this.classes.container;
       
  1084 
       
  1085 					/* Row selection config */
       
  1086 					if (this.s.select.type != 'none') {
       
  1087 						this._fnRowSelectConfig();
       
  1088 					}
       
  1089 
       
  1090 					/* Buttons */
       
  1091 					this._fnButtonDefinations(this.s.buttonSet, this.dom.container);
       
  1092 
       
  1093 					/* Destructor */
       
  1094 					this.s.dt.aoDestroyCallback.push({
       
  1095 														 "sName": "TableTools",
       
  1096 														 "fn": function () {
       
  1097 															 $(that.s.dt.nTBody).off('click.DTTT_Select', 'tr');
       
  1098 															 $(that.dom.container).empty();
       
  1099 														 }
       
  1100 													 });
       
  1101 				},
       
  1102 
       
  1103 
       
  1104 				/**
       
  1105 				 * Take the user defined settings and the default settings and combine them.
       
  1106 				 *  @method  _fnCustomiseSettings
       
  1107 				 *  @param   {Object} oOpts Same as TableTools constructor
       
  1108 				 *  @returns void
       
  1109 				 *  @private
       
  1110 				 */
       
  1111 				"_fnCustomiseSettings": function (oOpts) {
       
  1112 					/* Is this the master control instance or not? */
       
  1113 					if (typeof this.s.dt._TableToolsInit == 'undefined') {
       
  1114 						this.s.master = true;
       
  1115 						this.s.dt._TableToolsInit = true;
       
  1116 					}
       
  1117 
       
  1118 					/* We can use the table node from comparisons to group controls */
       
  1119 					this.dom.table = this.s.dt.nTable;
       
  1120 
       
  1121 					/* Clone the defaults and then the user options */
       
  1122 					this.s.custom = $.extend({}, TableTools.DEFAULTS, oOpts);
       
  1123 
       
  1124 					/* Flash file location */
       
  1125 					this.s.swfPath = this.s.custom.sSwfPath;
       
  1126 					if (typeof ZeroClipboard_TableTools != 'undefined') {
       
  1127 						ZeroClipboard_TableTools.moviePath = this.s.swfPath;
       
  1128 					}
       
  1129 
       
  1130 					/* Table row selecting */
       
  1131 					this.s.select.type = this.s.custom.sRowSelect;
       
  1132 					this.s.select.preRowSelect = this.s.custom.fnPreRowSelect;
       
  1133 					this.s.select.postSelected = this.s.custom.fnRowSelected;
       
  1134 					this.s.select.postDeselected = this.s.custom.fnRowDeselected;
       
  1135 
       
  1136 					// Backwards compatibility - allow the user to specify a custom class in the initialiser
       
  1137 					if (this.s.custom.sSelectedClass) {
       
  1138 						this.classes.select.row = this.s.custom.sSelectedClass;
       
  1139 					}
       
  1140 
       
  1141 					this.s.tags = this.s.custom.oTags;
       
  1142 
       
  1143 					/* Button set */
       
  1144 					this.s.buttonSet = this.s.custom.aButtons;
       
  1145 				},
       
  1146 
       
  1147 
       
  1148 				/**
       
  1149 				 * Take the user input arrays and expand them to be fully defined, and then add them to a given
       
  1150 				 * DOM element
       
  1151 				 *  @method  _fnButtonDefinations
       
  1152 				 *  @param {array} buttonSet Set of user defined buttons
       
  1153 				 *  @param {node} wrapper Node to add the created buttons to
       
  1154 				 *  @returns void
       
  1155 				 *  @private
       
  1156 				 */
       
  1157 				"_fnButtonDefinations": function (buttonSet, wrapper) {
       
  1158 					var buttonDef;
       
  1159 
       
  1160 					for (var i = 0, iLen = buttonSet.length; i < iLen; i++) {
       
  1161 						if (typeof buttonSet[i] == "string") {
       
  1162 							if (typeof TableTools.BUTTONS[ buttonSet[i] ] == 'undefined') {
       
  1163 								alert("TableTools: Warning - unknown button type: " + buttonSet[i]);
       
  1164 								continue;
       
  1165 							}
       
  1166 							buttonDef = $.extend({}, TableTools.BUTTONS[ buttonSet[i] ], true);
       
  1167 						}
       
  1168 						else {
       
  1169 							if (typeof TableTools.BUTTONS[ buttonSet[i].sExtends ] == 'undefined') {
       
  1170 								alert("TableTools: Warning - unknown button type: " + buttonSet[i].sExtends);
       
  1171 								continue;
       
  1172 							}
       
  1173 							var o = $.extend({}, TableTools.BUTTONS[ buttonSet[i].sExtends ], true);
       
  1174 							buttonDef = $.extend(o, buttonSet[i], true);
       
  1175 						}
       
  1176 
       
  1177 						wrapper.appendChild(this._fnCreateButton(
       
  1178 							buttonDef,
       
  1179 							$(wrapper).hasClass(this.classes.collection.container)
       
  1180 						));
       
  1181 					}
       
  1182 				},
       
  1183 
       
  1184 
       
  1185 				/**
       
  1186 				 * Create and configure a TableTools button
       
  1187 				 *  @method  _fnCreateButton
       
  1188 				 *  @param   {Object} oConfig Button configuration object
       
  1189 				 *  @returns {Node} Button element
       
  1190 				 *  @private
       
  1191 				 */
       
  1192 				"_fnCreateButton": function (oConfig, bCollectionButton) {
       
  1193 					var nButton = this._fnButtonBase(oConfig, bCollectionButton);
       
  1194 
       
  1195 					if (oConfig.sAction.match(/flash/)) {
       
  1196 						this._fnFlashConfig(nButton, oConfig);
       
  1197 					}
       
  1198 					else if (oConfig.sAction == "text") {
       
  1199 						this._fnTextConfig(nButton, oConfig);
       
  1200 					}
       
  1201 					else if (oConfig.sAction == "div") {
       
  1202 						this._fnTextConfig(nButton, oConfig);
       
  1203 					}
       
  1204 					else if (oConfig.sAction == "collection") {
       
  1205 						this._fnTextConfig(nButton, oConfig);
       
  1206 						this._fnCollectionConfig(nButton, oConfig);
       
  1207 					}
       
  1208 
       
  1209 					return nButton;
       
  1210 				},
       
  1211 
       
  1212 
       
  1213 				/**
       
  1214 				 * Create the DOM needed for the button and apply some base properties. All buttons start here
       
  1215 				 *  @method  _fnButtonBase
       
  1216 				 *  @param   {o} oConfig Button configuration object
       
  1217 				 *  @returns {Node} DIV element for the button
       
  1218 				 *  @private
       
  1219 				 */
       
  1220 				"_fnButtonBase": function (o, bCollectionButton) {
       
  1221 					var sTag, sLiner, sClass;
       
  1222 
       
  1223 					if (bCollectionButton) {
       
  1224 						sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.collection.button;
       
  1225 						sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.collection.liner;
       
  1226 						sClass = this.classes.collection.buttons.normal;
       
  1227 					}
       
  1228 					else {
       
  1229 						sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.button;
       
  1230 						sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.liner;
       
  1231 						sClass = this.classes.buttons.normal;
       
  1232 					}
       
  1233 
       
  1234 					var
       
  1235 						nButton = document.createElement(sTag),
       
  1236 						nSpan = document.createElement(sLiner),
       
  1237 						masterS = this._fnGetMasterSettings();
       
  1238 
       
  1239 					nButton.className = sClass + " " + o.sButtonClass;
       
  1240 					nButton.setAttribute('id', "ToolTables_" + this.s.dt.sInstance + "_" + masterS.buttonCounter);
       
  1241 					nButton.appendChild(nSpan);
       
  1242 					nSpan.innerHTML = o.sButtonText;
       
  1243 
       
  1244 					masterS.buttonCounter++;
       
  1245 
       
  1246 					return nButton;
       
  1247 				},
       
  1248 
       
  1249 
       
  1250 				/**
       
  1251 				 * Get the settings object for the master instance. When more than one TableTools instance is
       
  1252 				 * assigned to a DataTable, only one of them can be the 'master' (for the select rows). As such,
       
  1253 				 * we will typically want to interact with that master for global properties.
       
  1254 				 *  @method  _fnGetMasterSettings
       
  1255 				 *  @returns {Object} TableTools settings object
       
  1256 				 *  @private
       
  1257 				 */
       
  1258 				"_fnGetMasterSettings": function () {
       
  1259 					if (this.s.master) {
       
  1260 						return this.s;
       
  1261 					}
       
  1262 					else {
       
  1263 						/* Look for the master which has the same DT as this one */
       
  1264 						var instances = TableTools._aInstances;
       
  1265 						for (var i = 0, iLen = instances.length; i < iLen; i++) {
       
  1266 							if (this.dom.table == instances[i].s.dt.nTable) {
       
  1267 								return instances[i].s;
       
  1268 							}
       
  1269 						}
       
  1270 					}
       
  1271 				},
       
  1272 
       
  1273 
       
  1274 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1275 				 * Button collection functions
       
  1276 				 */
       
  1277 
       
  1278 				/**
       
  1279 				 * Create a collection button, when activated will present a drop down list of other buttons
       
  1280 				 *  @param   {Node} nButton Button to use for the collection activation
       
  1281 				 *  @param   {Object} oConfig Button configuration object
       
  1282 				 *  @returns void
       
  1283 				 *  @private
       
  1284 				 */
       
  1285 				"_fnCollectionConfig": function (nButton, oConfig) {
       
  1286 					var nHidden = document.createElement(this.s.tags.collection.container);
       
  1287 					nHidden.style.display = "none";
       
  1288 					nHidden.className = this.classes.collection.container;
       
  1289 					oConfig._collection = nHidden;
       
  1290 					document.body.appendChild(nHidden);
       
  1291 
       
  1292 					this._fnButtonDefinations(oConfig.aButtons, nHidden);
       
  1293 				},
       
  1294 
       
  1295 
       
  1296 				/**
       
  1297 				 * Show a button collection
       
  1298 				 *  @param   {Node} nButton Button to use for the collection
       
  1299 				 *  @param   {Object} oConfig Button configuration object
       
  1300 				 *  @returns void
       
  1301 				 *  @private
       
  1302 				 */
       
  1303 				"_fnCollectionShow": function (nButton, oConfig) {
       
  1304 					var
       
  1305 						that = this,
       
  1306 						oPos = $(nButton).offset(),
       
  1307 						nHidden = oConfig._collection,
       
  1308 						iDivX = oPos.left,
       
  1309 						iDivY = oPos.top + $(nButton).outerHeight(),
       
  1310 						iWinHeight = $(window).height(), iDocHeight = $(document).height(),
       
  1311 						iWinWidth = $(window).width(), iDocWidth = $(document).width();
       
  1312 
       
  1313 					nHidden.style.position = "absolute";
       
  1314 					nHidden.style.left = iDivX + "px";
       
  1315 					nHidden.style.top = iDivY + "px";
       
  1316 					nHidden.style.display = "block";
       
  1317 					$(nHidden).css('opacity', 0);
       
  1318 
       
  1319 					var nBackground = document.createElement('div');
       
  1320 					nBackground.style.position = "absolute";
       
  1321 					nBackground.style.left = "0px";
       
  1322 					nBackground.style.top = "0px";
       
  1323 					nBackground.style.height = ((iWinHeight > iDocHeight) ? iWinHeight : iDocHeight) + "px";
       
  1324 					nBackground.style.width = ((iWinWidth > iDocWidth) ? iWinWidth : iDocWidth) + "px";
       
  1325 					nBackground.className = this.classes.collection.background;
       
  1326 					$(nBackground).css('opacity', 0);
       
  1327 
       
  1328 					document.body.appendChild(nBackground);
       
  1329 					document.body.appendChild(nHidden);
       
  1330 
       
  1331 					/* Visual corrections to try and keep the collection visible */
       
  1332 					var iDivWidth = $(nHidden).outerWidth();
       
  1333 					var iDivHeight = $(nHidden).outerHeight();
       
  1334 
       
  1335 					if (iDivX + iDivWidth > iDocWidth) {
       
  1336 						nHidden.style.left = (iDocWidth - iDivWidth) + "px";
       
  1337 					}
       
  1338 
       
  1339 					if (iDivY + iDivHeight > iDocHeight) {
       
  1340 						nHidden.style.top = (iDivY - iDivHeight - $(nButton).outerHeight()) + "px";
       
  1341 					}
       
  1342 
       
  1343 					this.dom.collection.collection = nHidden;
       
  1344 					this.dom.collection.background = nBackground;
       
  1345 
       
  1346 					/* This results in a very small delay for the end user but it allows the animation to be
       
  1347 					 * much smoother. If you don't want the animation, then the setTimeout can be removed
       
  1348 					 */
       
  1349 					setTimeout(function () {
       
  1350 						$(nHidden).animate({"opacity": 1}, 500);
       
  1351 						$(nBackground).animate({"opacity": 0.25}, 500);
       
  1352 					}, 10);
       
  1353 
       
  1354 					/* Resize the buttons to the Flash contents fit */
       
  1355 					this.fnResizeButtons();
       
  1356 
       
  1357 					/* Event handler to remove the collection display */
       
  1358 					$(nBackground).click(function () {
       
  1359 						that._fnCollectionHide.call(that, null, null);
       
  1360 					});
       
  1361 				},
       
  1362 
       
  1363 
       
  1364 				/**
       
  1365 				 * Hide a button collection
       
  1366 				 *  @param   {Node} nButton Button to use for the collection
       
  1367 				 *  @param   {Object} oConfig Button configuration object
       
  1368 				 *  @returns void
       
  1369 				 *  @private
       
  1370 				 */
       
  1371 				"_fnCollectionHide": function (nButton, oConfig) {
       
  1372 					if (oConfig !== null && oConfig.sExtends == 'collection') {
       
  1373 						return;
       
  1374 					}
       
  1375 
       
  1376 					if (this.dom.collection.collection !== null) {
       
  1377 						$(this.dom.collection.collection).animate({"opacity": 0}, 500, function (e) {
       
  1378 							this.style.display = "none";
       
  1379 						});
       
  1380 
       
  1381 						$(this.dom.collection.background).animate({"opacity": 0}, 500, function (e) {
       
  1382 							this.parentNode.removeChild(this);
       
  1383 						});
       
  1384 
       
  1385 						this.dom.collection.collection = null;
       
  1386 						this.dom.collection.background = null;
       
  1387 					}
       
  1388 				},
       
  1389 
       
  1390 
       
  1391 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1392 				 * Row selection functions
       
  1393 				 */
       
  1394 
       
  1395 				/**
       
  1396 				 * Add event handlers to a table to allow for row selection
       
  1397 				 *  @method  _fnRowSelectConfig
       
  1398 				 *  @returns void
       
  1399 				 *  @private
       
  1400 				 */
       
  1401 				"_fnRowSelectConfig": function () {
       
  1402 					if (this.s.master) {
       
  1403 						var
       
  1404 							that = this,
       
  1405 							i, iLen,
       
  1406 							dt = this.s.dt,
       
  1407 							aoOpenRows = this.s.dt.aoOpenRows;
       
  1408 
       
  1409 						$(dt.nTable).addClass(this.classes.select.table);
       
  1410 
       
  1411 						// When using OS style selection, we want to cancel the shift text
       
  1412 						// selection, but only when the shift key is used (so you can
       
  1413 						// actually still select text in the table)
       
  1414 						if (this.s.select.type === 'os') {
       
  1415 							$(dt.nTBody).on('mousedown.DTTT_Select', 'tr', function (e) {
       
  1416 								if (e.shiftKey) {
       
  1417 
       
  1418 									$(dt.nTBody)
       
  1419 										.css('-moz-user-select', 'none')
       
  1420 										.one('selectstart.DTTT_Select', 'tr', function () {
       
  1421 												 return false;
       
  1422 											 });
       
  1423 								}
       
  1424 							});
       
  1425 
       
  1426 							$(dt.nTBody).on('mouseup.DTTT_Select', 'tr', function (e) {
       
  1427 								$(dt.nTBody).css('-moz-user-select', '');
       
  1428 							});
       
  1429 						}
       
  1430 
       
  1431 						// Row selection
       
  1432 						$(dt.nTBody).on('click.DTTT_Select', 'tr', function (e) {
       
  1433 							var select = that.s.select;
       
  1434 							var pos = that.s.dt.oInstance.fnGetPosition(this);
       
  1435 
       
  1436 							/* Sub-table must be ignored (odd that the selector won't do this with >) */
       
  1437 							if (this.parentNode != dt.nTBody) {
       
  1438 								return;
       
  1439 							}
       
  1440 
       
  1441 							/* Check that we are actually working with a DataTables controlled row */
       
  1442 							if (dt.oInstance.fnGetData(this) === null) {
       
  1443 								return;
       
  1444 							}
       
  1445 
       
  1446 							// Shift click, ctrl click and simple click handling to make
       
  1447 							// row selection a lot like a file system in desktop OSs
       
  1448 							if (select.type == 'os') {
       
  1449 								if (e.ctrlKey || e.metaKey) {
       
  1450 									// Add or remove from the selection
       
  1451 									if (that.fnIsSelected(this)) {
       
  1452 										that._fnRowDeselect(this, e);
       
  1453 									}
       
  1454 									else {
       
  1455 										that._fnRowSelect(this, e);
       
  1456 									}
       
  1457 								}
       
  1458 								else if (e.shiftKey) {
       
  1459 									// Add a range of rows, from the last selected row to
       
  1460 									// this one
       
  1461 									var rowIdxs = that.s.dt.aiDisplay.slice(); // visible rows
       
  1462 									var idx1 = $.inArray(select.lastRow, rowIdxs);
       
  1463 									var idx2 = $.inArray(pos, rowIdxs);
       
  1464 
       
  1465 									if (that.fnGetSelected().length === 0 || idx1 === -1) {
       
  1466 										// select from top to here - slightly odd, but both
       
  1467 										// Windows and Mac OS do this
       
  1468 										rowIdxs.splice($.inArray(pos, rowIdxs) + 1, rowIdxs.length);
       
  1469 									}
       
  1470 									else {
       
  1471 										// reverse so we can shift click 'up' as well as down
       
  1472 										if (idx1 > idx2) {
       
  1473 											var tmp = idx2;
       
  1474 											idx2 = idx1;
       
  1475 											idx1 = tmp;
       
  1476 										}
       
  1477 
       
  1478 										rowIdxs.splice(idx2 + 1, rowIdxs.length);
       
  1479 										rowIdxs.splice(0, idx1);
       
  1480 									}
       
  1481 
       
  1482 									if (!that.fnIsSelected(this)) {
       
  1483 										// Select range
       
  1484 										that._fnRowSelect(rowIdxs, e);
       
  1485 									}
       
  1486 									else {
       
  1487 										// Deselect range - need to keep the clicked on row selected
       
  1488 										rowIdxs.splice($.inArray(pos, rowIdxs), 1);
       
  1489 										that._fnRowDeselect(rowIdxs, e);
       
  1490 									}
       
  1491 								}
       
  1492 								else {
       
  1493 									// No cmd or shift click. Deselect current if selected,
       
  1494 									// or select this row only
       
  1495 									if (that.fnIsSelected(this) && that.fnGetSelected().length === 1) {
       
  1496 										that._fnRowDeselect(this, e);
       
  1497 									}
       
  1498 									else {
       
  1499 										that.fnSelectNone();
       
  1500 										that._fnRowSelect(this, e);
       
  1501 									}
       
  1502 								}
       
  1503 							}
       
  1504 							else if (that.fnIsSelected(this)) {
       
  1505 								that._fnRowDeselect(this, e);
       
  1506 							}
       
  1507 							else if (select.type == "single") {
       
  1508 								that.fnSelectNone();
       
  1509 								that._fnRowSelect(this, e);
       
  1510 							}
       
  1511 							else if (select.type == "multi") {
       
  1512 								that._fnRowSelect(this, e);
       
  1513 							}
       
  1514 
       
  1515 							select.lastRow = pos;
       
  1516 						});//.on('selectstart', function () { return false; } );
       
  1517 
       
  1518 						// Bind a listener to the DataTable for when new rows are created.
       
  1519 						// This allows rows to be visually selected when they should be and
       
  1520 						// deferred rendering is used.
       
  1521 						dt.oApi._fnCallbackReg(dt, 'aoRowCreatedCallback', function (tr, data, index) {
       
  1522 							if (dt.aoData[index]._DTTT_selected) {
       
  1523 								$(tr).addClass(that.classes.select.row);
       
  1524 							}
       
  1525 						}, 'TableTools-SelectAll');
       
  1526 					}
       
  1527 				},
       
  1528 
       
  1529 				/**
       
  1530 				 * Select rows
       
  1531 				 *  @param   {*} src Rows to select - see _fnSelectData for a description of valid inputs
       
  1532 				 *  @private
       
  1533 				 */
       
  1534 				"_fnRowSelect": function (src, e) {
       
  1535 					var
       
  1536 						that = this,
       
  1537 						data = this._fnSelectData(src),
       
  1538 						firstTr = data.length === 0 ? null : data[0].nTr,
       
  1539 						anSelected = [],
       
  1540 						i, len;
       
  1541 
       
  1542 					// Get all the rows that will be selected
       
  1543 					for (i = 0, len = data.length; i < len; i++) {
       
  1544 						if (data[i].nTr) {
       
  1545 							anSelected.push(data[i].nTr);
       
  1546 						}
       
  1547 					}
       
  1548 
       
  1549 					// User defined pre-selection function
       
  1550 					if (this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anSelected, true)) {
       
  1551 						return;
       
  1552 					}
       
  1553 
       
  1554 					// Mark them as selected
       
  1555 					for (i = 0, len = data.length; i < len; i++) {
       
  1556 						data[i]._DTTT_selected = true;
       
  1557 
       
  1558 						if (data[i].nTr) {
       
  1559 							$(data[i].nTr).addClass(that.classes.select.row);
       
  1560 						}
       
  1561 					}
       
  1562 
       
  1563 					// Post-selection function
       
  1564 					if (this.s.select.postSelected !== null) {
       
  1565 						this.s.select.postSelected.call(this, anSelected);
       
  1566 					}
       
  1567 
       
  1568 					TableTools._fnEventDispatch(this, 'select', anSelected, true);
       
  1569 				},
       
  1570 
       
  1571 				/**
       
  1572 				 * Deselect rows
       
  1573 				 *  @param   {*} src Rows to deselect - see _fnSelectData for a description of valid inputs
       
  1574 				 *  @private
       
  1575 				 */
       
  1576 				"_fnRowDeselect": function (src, e) {
       
  1577 					var
       
  1578 						that = this,
       
  1579 						data = this._fnSelectData(src),
       
  1580 						firstTr = data.length === 0 ? null : data[0].nTr,
       
  1581 						anDeselectedTrs = [],
       
  1582 						i, len;
       
  1583 
       
  1584 					// Get all the rows that will be deselected
       
  1585 					for (i = 0, len = data.length; i < len; i++) {
       
  1586 						if (data[i].nTr) {
       
  1587 							anDeselectedTrs.push(data[i].nTr);
       
  1588 						}
       
  1589 					}
       
  1590 
       
  1591 					// User defined pre-selection function
       
  1592 					if (this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anDeselectedTrs, false)) {
       
  1593 						return;
       
  1594 					}
       
  1595 
       
  1596 					// Mark them as deselected
       
  1597 					for (i = 0, len = data.length; i < len; i++) {
       
  1598 						data[i]._DTTT_selected = false;
       
  1599 
       
  1600 						if (data[i].nTr) {
       
  1601 							$(data[i].nTr).removeClass(that.classes.select.row);
       
  1602 						}
       
  1603 					}
       
  1604 
       
  1605 					// Post-deselection function
       
  1606 					if (this.s.select.postDeselected !== null) {
       
  1607 						this.s.select.postDeselected.call(this, anDeselectedTrs);
       
  1608 					}
       
  1609 
       
  1610 					TableTools._fnEventDispatch(this, 'select', anDeselectedTrs, false);
       
  1611 				},
       
  1612 
       
  1613 				/**
       
  1614 				 * Take a data source for row selection and convert it into aoData points for the DT
       
  1615 				 *   @param {*} src Can be a single DOM TR node, an array of TR nodes (including a
       
  1616 				 *     a jQuery object), a single aoData point from DataTables, an array of aoData
       
  1617 				 *     points or an array of aoData indexes
       
  1618 				 *   @returns {array} An array of aoData points
       
  1619 				 */
       
  1620 				"_fnSelectData": function (src) {
       
  1621 					var out = [], pos, i, iLen;
       
  1622 
       
  1623 					if (src.nodeName) {
       
  1624 						// Single node
       
  1625 						pos = this.s.dt.oInstance.fnGetPosition(src);
       
  1626 						out.push(this.s.dt.aoData[pos]);
       
  1627 					}
       
  1628 					else if (typeof src.length !== 'undefined') {
       
  1629 						// jQuery object or an array of nodes, or aoData points
       
  1630 						for (i = 0, iLen = src.length; i < iLen; i++) {
       
  1631 							if (src[i].nodeName) {
       
  1632 								pos = this.s.dt.oInstance.fnGetPosition(src[i]);
       
  1633 								out.push(this.s.dt.aoData[pos]);
       
  1634 							}
       
  1635 							else if (typeof src[i] === 'number') {
       
  1636 								out.push(this.s.dt.aoData[ src[i] ]);
       
  1637 							}
       
  1638 							else {
       
  1639 								out.push(src[i]);
       
  1640 							}
       
  1641 						}
       
  1642 
       
  1643 						return out;
       
  1644 					}
       
  1645 					else {
       
  1646 						// A single aoData point
       
  1647 						out.push(src);
       
  1648 					}
       
  1649 
       
  1650 					return out;
       
  1651 				},
       
  1652 
       
  1653 
       
  1654 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1655 				 * Text button functions
       
  1656 				 */
       
  1657 
       
  1658 				/**
       
  1659 				 * Configure a text based button for interaction events
       
  1660 				 *  @method  _fnTextConfig
       
  1661 				 *  @param   {Node} nButton Button element which is being considered
       
  1662 				 *  @param   {Object} oConfig Button configuration object
       
  1663 				 *  @returns void
       
  1664 				 *  @private
       
  1665 				 */
       
  1666 				"_fnTextConfig": function (nButton, oConfig) {
       
  1667 					var that = this;
       
  1668 
       
  1669 					if (oConfig.fnInit !== null) {
       
  1670 						oConfig.fnInit.call(this, nButton, oConfig);
       
  1671 					}
       
  1672 
       
  1673 					if (oConfig.sToolTip !== "") {
       
  1674 						nButton.title = oConfig.sToolTip;
       
  1675 					}
       
  1676 
       
  1677 					$(nButton).hover(function () {
       
  1678 						if (oConfig.fnMouseover !== null) {
       
  1679 							oConfig.fnMouseover.call(this, nButton, oConfig, null);
       
  1680 						}
       
  1681 					}, function () {
       
  1682 						if (oConfig.fnMouseout !== null) {
       
  1683 							oConfig.fnMouseout.call(this, nButton, oConfig, null);
       
  1684 						}
       
  1685 					});
       
  1686 
       
  1687 					if (oConfig.fnSelect !== null) {
       
  1688 						TableTools._fnEventListen(this, 'select', function (n) {
       
  1689 							oConfig.fnSelect.call(that, nButton, oConfig, n);
       
  1690 						});
       
  1691 					}
       
  1692 
       
  1693 					$(nButton).click(function (e) {
       
  1694 						//e.preventDefault();
       
  1695 
       
  1696 						if (oConfig.fnClick !== null) {
       
  1697 							oConfig.fnClick.call(that, nButton, oConfig, null, e);
       
  1698 						}
       
  1699 
       
  1700 						/* Provide a complete function to match the behaviour of the flash elements */
       
  1701 						if (oConfig.fnComplete !== null) {
       
  1702 							oConfig.fnComplete.call(that, nButton, oConfig, null, null);
       
  1703 						}
       
  1704 
       
  1705 						that._fnCollectionHide(nButton, oConfig);
       
  1706 					});
       
  1707 				},
       
  1708 
       
  1709 
       
  1710 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1711 				 * Flash button functions
       
  1712 				 */
       
  1713 
       
  1714 				/**
       
  1715 				 * Configure a flash based button for interaction events
       
  1716 				 *  @method  _fnFlashConfig
       
  1717 				 *  @param   {Node} nButton Button element which is being considered
       
  1718 				 *  @param   {o} oConfig Button configuration object
       
  1719 				 *  @returns void
       
  1720 				 *  @private
       
  1721 				 */
       
  1722 				"_fnFlashConfig": function (nButton, oConfig) {
       
  1723 					var that = this;
       
  1724 					var flash = new ZeroClipboard_TableTools.Client();
       
  1725 
       
  1726 					if (oConfig.fnInit !== null) {
       
  1727 						oConfig.fnInit.call(this, nButton, oConfig);
       
  1728 					}
       
  1729 
       
  1730 					flash.setHandCursor(true);
       
  1731 
       
  1732 					if (oConfig.sAction == "flash_save") {
       
  1733 						flash.setAction('save');
       
  1734 						flash.setCharSet((oConfig.sCharSet == "utf16le") ? 'UTF16LE' : 'UTF8');
       
  1735 						flash.setBomInc(oConfig.bBomInc);
       
  1736 						flash.setFileName(oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)));
       
  1737 					}
       
  1738 					else if (oConfig.sAction == "flash_pdf") {
       
  1739 						flash.setAction('pdf');
       
  1740 						flash.setFileName(oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)));
       
  1741 					}
       
  1742 					else {
       
  1743 						flash.setAction('copy');
       
  1744 					}
       
  1745 
       
  1746 					flash.addEventListener('mouseOver', function (client) {
       
  1747 						if (oConfig.fnMouseover !== null) {
       
  1748 							oConfig.fnMouseover.call(that, nButton, oConfig, flash);
       
  1749 						}
       
  1750 					});
       
  1751 
       
  1752 					flash.addEventListener('mouseOut', function (client) {
       
  1753 						if (oConfig.fnMouseout !== null) {
       
  1754 							oConfig.fnMouseout.call(that, nButton, oConfig, flash);
       
  1755 						}
       
  1756 					});
       
  1757 
       
  1758 					flash.addEventListener('mouseDown', function (client) {
       
  1759 						if (oConfig.fnClick !== null) {
       
  1760 							oConfig.fnClick.call(that, nButton, oConfig, flash);
       
  1761 						}
       
  1762 					});
       
  1763 
       
  1764 					flash.addEventListener('complete', function (client, text) {
       
  1765 						if (oConfig.fnComplete !== null) {
       
  1766 							oConfig.fnComplete.call(that, nButton, oConfig, flash, text);
       
  1767 						}
       
  1768 						that._fnCollectionHide(nButton, oConfig);
       
  1769 					});
       
  1770 
       
  1771 					this._fnFlashGlue(flash, nButton, oConfig.sToolTip);
       
  1772 				},
       
  1773 
       
  1774 
       
  1775 				/**
       
  1776 				 * Wait until the id is in the DOM before we "glue" the swf. Note that this function will call
       
  1777 				 * itself (using setTimeout) until it completes successfully
       
  1778 				 *  @method  _fnFlashGlue
       
  1779 				 *  @param   {Object} clip Zero clipboard object
       
  1780 				 *  @param   {Node} node node to glue swf to
       
  1781 				 *  @param   {String} text title of the flash movie
       
  1782 				 *  @returns void
       
  1783 				 *  @private
       
  1784 				 */
       
  1785 				"_fnFlashGlue": function (flash, node, text) {
       
  1786 					var that = this;
       
  1787 					var id = node.getAttribute('id');
       
  1788 
       
  1789 					if (document.getElementById(id)) {
       
  1790 						flash.glue(node, text);
       
  1791 					}
       
  1792 					else {
       
  1793 						setTimeout(function () {
       
  1794 							that._fnFlashGlue(flash, node, text);
       
  1795 						}, 100);
       
  1796 					}
       
  1797 				},
       
  1798 
       
  1799 
       
  1800 				/**
       
  1801 				 * Set the text for the flash clip to deal with
       
  1802 				 *
       
  1803 				 * This function is required for large information sets. There is a limit on the
       
  1804 				 * amount of data that can be transferred between Javascript and Flash in a single call, so
       
  1805 				 * we use this method to build up the text in Flash by sending over chunks. It is estimated
       
  1806 				 * that the data limit is around 64k, although it is undocumented, and appears to be different
       
  1807 				 * between different flash versions. We chunk at 8KiB.
       
  1808 				 *  @method  _fnFlashSetText
       
  1809 				 *  @param   {Object} clip the ZeroClipboard object
       
  1810 				 *  @param   {String} sData the data to be set
       
  1811 				 *  @returns void
       
  1812 				 *  @private
       
  1813 				 */
       
  1814 				"_fnFlashSetText": function (clip, sData) {
       
  1815 					var asData = this._fnChunkData(sData, 8192);
       
  1816 
       
  1817 					clip.clearText();
       
  1818 					for (var i = 0, iLen = asData.length; i < iLen; i++) {
       
  1819 						clip.appendText(asData[i]);
       
  1820 					}
       
  1821 				},
       
  1822 
       
  1823 
       
  1824 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  1825 				 * Data retrieval functions
       
  1826 				 */
       
  1827 
       
  1828 				/**
       
  1829 				 * Convert the mixed columns variable into a boolean array the same size as the columns, which
       
  1830 				 * indicates which columns we want to include
       
  1831 				 *  @method  _fnColumnTargets
       
  1832 				 *  @param   {String|Array} mColumns The columns to be included in data retrieval. If a string
       
  1833 				 *             then it can take the value of "visible" or "hidden" (to include all visible or
       
  1834 				 *             hidden columns respectively). Or an array of column indexes
       
  1835 				 *  @returns {Array} A boolean array the length of the columns of the table, which each value
       
  1836 				 *             indicating if the column is to be included or not
       
  1837 				 *  @private
       
  1838 				 */
       
  1839 				"_fnColumnTargets": function (mColumns) {
       
  1840 					var aColumns = [];
       
  1841 					var dt = this.s.dt;
       
  1842 					var i, iLen;
       
  1843 
       
  1844 					if (typeof mColumns == "object") {
       
  1845 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  1846 							aColumns.push(false);
       
  1847 						}
       
  1848 
       
  1849 						for (i = 0, iLen = mColumns.length; i < iLen; i++) {
       
  1850 							aColumns[ mColumns[i] ] = true;
       
  1851 						}
       
  1852 					}
       
  1853 					else if (mColumns == "visible") {
       
  1854 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  1855 							aColumns.push(dt.aoColumns[i].bVisible ? true : false);
       
  1856 						}
       
  1857 					}
       
  1858 					else if (mColumns == "hidden") {
       
  1859 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  1860 							aColumns.push(dt.aoColumns[i].bVisible ? false : true);
       
  1861 						}
       
  1862 					}
       
  1863 					else if (mColumns == "sortable") {
       
  1864 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  1865 							aColumns.push(dt.aoColumns[i].bSortable ? true : false);
       
  1866 						}
       
  1867 					}
       
  1868 					else /* all */
       
  1869 					{
       
  1870 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  1871 							aColumns.push(true);
       
  1872 						}
       
  1873 					}
       
  1874 
       
  1875 					return aColumns;
       
  1876 				},
       
  1877 
       
  1878 
       
  1879 				/**
       
  1880 				 * New line character(s) depend on the platforms
       
  1881 				 *  @method  method
       
  1882 				 *  @param   {Object} oConfig Button configuration object - only interested in oConfig.sNewLine
       
  1883 				 *  @returns {String} Newline character
       
  1884 				 */
       
  1885 				"_fnNewline": function (oConfig) {
       
  1886 					if (oConfig.sNewLine == "auto") {
       
  1887 						return navigator.userAgent.match(/Windows/) ? "\r\n" : "\n";
       
  1888 					}
       
  1889 					else {
       
  1890 						return oConfig.sNewLine;
       
  1891 					}
       
  1892 				},
       
  1893 
       
  1894 
       
  1895 				/**
       
  1896 				 * Get data from DataTables' internals and format it for output
       
  1897 				 *  @method  _fnGetDataTablesData
       
  1898 				 *  @param   {Object} oConfig Button configuration object
       
  1899 				 *  @param   {String} oConfig.sFieldBoundary Field boundary for the data cells in the string
       
  1900 				 *  @param   {String} oConfig.sFieldSeperator Field separator for the data cells
       
  1901 				 *  @param   {String} oConfig.sNewline New line options
       
  1902 				 *  @param   {Mixed} oConfig.mColumns Which columns should be included in the output
       
  1903 				 *  @param   {Boolean} oConfig.bHeader Include the header
       
  1904 				 *  @param   {Boolean} oConfig.bFooter Include the footer
       
  1905 				 *  @param   {Boolean} oConfig.bSelectedOnly Include only the selected rows in the output
       
  1906 				 *  @returns {String} Concatenated string of data
       
  1907 				 *  @private
       
  1908 				 */
       
  1909 				"_fnGetDataTablesData": function (oConfig) {
       
  1910 					var i, iLen, j, jLen;
       
  1911 					var aRow, aData = [], sLoopData = '', arr;
       
  1912 					var dt = this.s.dt, tr, child;
       
  1913 					var regex = new RegExp(oConfig.sFieldBoundary, "g");
       
  1914 					/* Do it here for speed */
       
  1915 					var aColumnsInc = this._fnColumnTargets(oConfig.mColumns);
       
  1916 					var bSelectedOnly = (typeof oConfig.bSelectedOnly != 'undefined') ? oConfig.bSelectedOnly : false;
       
  1917 
       
  1918 					/*
       
  1919 					 * Header
       
  1920 					 */
       
  1921 					if (oConfig.bHeader) {
       
  1922 						aRow = [];
       
  1923 
       
  1924 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  1925 							if (aColumnsInc[i]) {
       
  1926 								sLoopData = dt.aoColumns[i].sTitle.replace(/\n/g, " ").replace(/<.*?>/g, "").replace(/^\s+|\s+$/g, "");
       
  1927 								sLoopData = this._fnHtmlDecode(sLoopData);
       
  1928 
       
  1929 								aRow.push(this._fnBoundData(sLoopData, oConfig.sFieldBoundary, regex));
       
  1930 							}
       
  1931 						}
       
  1932 
       
  1933 						aData.push(aRow.join(oConfig.sFieldSeperator));
       
  1934 					}
       
  1935 
       
  1936 					/*
       
  1937 					 * Body
       
  1938 					 */
       
  1939 					var aSelected = this.fnGetSelected();
       
  1940 					bSelectedOnly = this.s.select.type !== "none" && bSelectedOnly && aSelected.length !== 0;
       
  1941 
       
  1942 					var aDataIndex = dt.oInstance
       
  1943 						.$('tr', oConfig.oSelectorOpts)
       
  1944 						.map(function (id, row) {
       
  1945 								 // If "selected only", then ensure that the row is in the selected list
       
  1946 								 return bSelectedOnly && $.inArray(row, aSelected) === -1 ?
       
  1947 									 null :
       
  1948 									 dt.oInstance.fnGetPosition(row);
       
  1949 							 })
       
  1950 						.get();
       
  1951 
       
  1952 					for (j = 0, jLen = aDataIndex.length; j < jLen; j++) {
       
  1953 						tr = dt.aoData[ aDataIndex[j] ].nTr;
       
  1954 						aRow = [];
       
  1955 
       
  1956 						/* Columns */
       
  1957 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  1958 							if (aColumnsInc[i]) {
       
  1959 								/* Convert to strings (with small optimisation) */
       
  1960 								var mTypeData = dt.oApi._fnGetCellData(dt, aDataIndex[j], i, 'display');
       
  1961 								if (oConfig.fnCellRender) {
       
  1962 									sLoopData = oConfig.fnCellRender(mTypeData, i, tr, aDataIndex[j]) + "";
       
  1963 								}
       
  1964 								else if (typeof mTypeData == "string") {
       
  1965 									/* Strip newlines, replace img tags with alt attr. and finally strip html... */
       
  1966 									sLoopData = mTypeData.replace(/\n/g, " ");
       
  1967 									sLoopData =
       
  1968 										sLoopData.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi,
       
  1969 														  '$1$2$3');
       
  1970 									sLoopData = sLoopData.replace(/<.*?>/g, "");
       
  1971 								}
       
  1972 								else {
       
  1973 									sLoopData = mTypeData + "";
       
  1974 								}
       
  1975 
       
  1976 								/* Trim and clean the data */
       
  1977 								sLoopData = sLoopData.replace(/^\s+/, '').replace(/\s+$/, '');
       
  1978 								sLoopData = this._fnHtmlDecode(sLoopData);
       
  1979 
       
  1980 								/* Bound it and add it to the total data */
       
  1981 								aRow.push(this._fnBoundData(sLoopData, oConfig.sFieldBoundary, regex));
       
  1982 							}
       
  1983 						}
       
  1984 
       
  1985 						aData.push(aRow.join(oConfig.sFieldSeperator));
       
  1986 
       
  1987 						/* Details rows from fnOpen */
       
  1988 						if (oConfig.bOpenRows) {
       
  1989 							arr = $.grep(dt.aoOpenRows, function (o) {
       
  1990 								return o.nParent === tr;
       
  1991 							});
       
  1992 
       
  1993 							if (arr.length === 1) {
       
  1994 								sLoopData = this._fnBoundData($('td', arr[0].nTr).html(), oConfig.sFieldBoundary, regex);
       
  1995 								aData.push(sLoopData);
       
  1996 							}
       
  1997 						}
       
  1998 					}
       
  1999 
       
  2000 					/*
       
  2001 					 * Footer
       
  2002 					 */
       
  2003 					if (oConfig.bFooter && dt.nTFoot !== null) {
       
  2004 						aRow = [];
       
  2005 
       
  2006 						for (i = 0, iLen = dt.aoColumns.length; i < iLen; i++) {
       
  2007 							if (aColumnsInc[i] && dt.aoColumns[i].nTf !== null) {
       
  2008 								sLoopData = dt.aoColumns[i].nTf.innerHTML.replace(/\n/g, " ").replace(/<.*?>/g, "");
       
  2009 								sLoopData = this._fnHtmlDecode(sLoopData);
       
  2010 
       
  2011 								aRow.push(this._fnBoundData(sLoopData, oConfig.sFieldBoundary, regex));
       
  2012 							}
       
  2013 						}
       
  2014 
       
  2015 						aData.push(aRow.join(oConfig.sFieldSeperator));
       
  2016 					}
       
  2017 
       
  2018 					var _sLastData = aData.join(this._fnNewline(oConfig));
       
  2019 					return _sLastData;
       
  2020 				},
       
  2021 
       
  2022 
       
  2023 				/**
       
  2024 				 * Wrap data up with a boundary string
       
  2025 				 *  @method  _fnBoundData
       
  2026 				 *  @param   {String} sData data to bound
       
  2027 				 *  @param   {String} sBoundary bounding char(s)
       
  2028 				 *  @param   {RegExp} regex search for the bounding chars - constructed outside for efficiency
       
  2029 				 *             in the loop
       
  2030 				 *  @returns {String} bound data
       
  2031 				 *  @private
       
  2032 				 */
       
  2033 				"_fnBoundData": function (sData, sBoundary, regex) {
       
  2034 					if (sBoundary === "") {
       
  2035 						return sData;
       
  2036 					}
       
  2037 					else {
       
  2038 						return sBoundary + sData.replace(regex, sBoundary + sBoundary) + sBoundary;
       
  2039 					}
       
  2040 				},
       
  2041 
       
  2042 
       
  2043 				/**
       
  2044 				 * Break a string up into an array of smaller strings
       
  2045 				 *  @method  _fnChunkData
       
  2046 				 *  @param   {String} sData data to be broken up
       
  2047 				 *  @param   {Int} iSize chunk size
       
  2048 				 *  @returns {Array} String array of broken up text
       
  2049 				 *  @private
       
  2050 				 */
       
  2051 				"_fnChunkData": function (sData, iSize) {
       
  2052 					var asReturn = [];
       
  2053 					var iStrlen = sData.length;
       
  2054 
       
  2055 					for (var i = 0; i < iStrlen; i += iSize) {
       
  2056 						if (i + iSize < iStrlen) {
       
  2057 							asReturn.push(sData.substring(i, i + iSize));
       
  2058 						}
       
  2059 						else {
       
  2060 							asReturn.push(sData.substring(i, iStrlen));
       
  2061 						}
       
  2062 					}
       
  2063 
       
  2064 					return asReturn;
       
  2065 				},
       
  2066 
       
  2067 
       
  2068 				/**
       
  2069 				 * Decode HTML entities
       
  2070 				 *  @method  _fnHtmlDecode
       
  2071 				 *  @param   {String} sData encoded string
       
  2072 				 *  @returns {String} decoded string
       
  2073 				 *  @private
       
  2074 				 */
       
  2075 				"_fnHtmlDecode": function (sData) {
       
  2076 					if (sData.indexOf('&') === -1) {
       
  2077 						return sData;
       
  2078 					}
       
  2079 
       
  2080 					var n = document.createElement('div');
       
  2081 
       
  2082 					return sData.replace(/&([^\s]*);/g, function (match, match2) {
       
  2083 						if (match.substr(1, 1) === '#') {
       
  2084 							return String.fromCharCode(Number(match2.substr(1)));
       
  2085 						}
       
  2086 						else {
       
  2087 							n.innerHTML = match;
       
  2088 							return n.childNodes[0].nodeValue;
       
  2089 						}
       
  2090 					});
       
  2091 				},
       
  2092 
       
  2093 
       
  2094 				/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  2095 				 * Printing functions
       
  2096 				 */
       
  2097 
       
  2098 				/**
       
  2099 				 * Show print display
       
  2100 				 *  @method  _fnPrintStart
       
  2101 				 *  @param   {Event} e Event object
       
  2102 				 *  @param   {Object} oConfig Button configuration object
       
  2103 				 *  @returns void
       
  2104 				 *  @private
       
  2105 				 */
       
  2106 				"_fnPrintStart": function (oConfig) {
       
  2107 					var that = this;
       
  2108 					var oSetDT = this.s.dt;
       
  2109 
       
  2110 					/* Parse through the DOM hiding everything that isn't needed for the table */
       
  2111 					this._fnPrintHideNodes(oSetDT.nTable);
       
  2112 
       
  2113 					/* Show the whole table */
       
  2114 					this.s.print.saveStart = oSetDT._iDisplayStart;
       
  2115 					this.s.print.saveLength = oSetDT._iDisplayLength;
       
  2116 
       
  2117 					if (oConfig.bShowAll) {
       
  2118 						oSetDT._iDisplayStart = 0;
       
  2119 						oSetDT._iDisplayLength = -1;
       
  2120 						if (oSetDT.oApi._fnCalculateEnd) {
       
  2121 							oSetDT.oApi._fnCalculateEnd(oSetDT);
       
  2122 						}
       
  2123 						oSetDT.oApi._fnDraw(oSetDT);
       
  2124 					}
       
  2125 
       
  2126 					/* Adjust the display for scrolling which might be done by DataTables */
       
  2127 					if (oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "") {
       
  2128 						this._fnPrintScrollStart(oSetDT);
       
  2129 
       
  2130 						// If the table redraws while in print view, the DataTables scrolling
       
  2131 						// setup would hide the header, so we need to readd it on draw
       
  2132 						$(this.s.dt.nTable).bind('draw.DTTT_Print', function () {
       
  2133 							that._fnPrintScrollStart(oSetDT);
       
  2134 						});
       
  2135 					}
       
  2136 
       
  2137 					/* Remove the other DataTables feature nodes - but leave the table! and info div */
       
  2138 					var anFeature = oSetDT.aanFeatures;
       
  2139 					for (var cFeature in anFeature) {
       
  2140 						if (cFeature != 'i' && cFeature != 't' && cFeature.length == 1) {
       
  2141 							for (var i = 0, iLen = anFeature[cFeature].length; i < iLen; i++) {
       
  2142 								this.dom.print.hidden.push({
       
  2143 															   "node": anFeature[cFeature][i],
       
  2144 															   "display": "block"
       
  2145 														   });
       
  2146 								anFeature[cFeature][i].style.display = "none";
       
  2147 							}
       
  2148 						}
       
  2149 					}
       
  2150 
       
  2151 					/* Print class can be used for styling */
       
  2152 					$(document.body).addClass(this.classes.print.body);
       
  2153 
       
  2154 					/* Show information message to let the user know what is happening */
       
  2155 					if (oConfig.sInfo !== "") {
       
  2156 						this.fnInfo(oConfig.sInfo, 3000);
       
  2157 					}
       
  2158 
       
  2159 					/* Add a message at the top of the page */
       
  2160 					if (oConfig.sMessage) {
       
  2161 						$('<div/>')
       
  2162 							.addClass(this.classes.print.message)
       
  2163 							.html(oConfig.sMessage)
       
  2164 							.prepend('body');
       
  2165 					}
       
  2166 
       
  2167 					/* Cache the scrolling and the jump to the top of the page */
       
  2168 					this.s.print.saveScroll = $(window).scrollTop();
       
  2169 					window.scrollTo(0, 0);
       
  2170 
       
  2171 					/* Bind a key event listener to the document for the escape key -
       
  2172 					 * it is removed in the callback
       
  2173 					 */
       
  2174 					$(document).bind("keydown.DTTT", function (e) {
       
  2175 						/* Only interested in the escape key */
       
  2176 						if (e.keyCode == 27) {
       
  2177 							e.preventDefault();
       
  2178 							that._fnPrintEnd.call(that, e);
       
  2179 						}
       
  2180 					});
       
  2181 				},
       
  2182 
       
  2183 
       
  2184 				/**
       
  2185 				 * Printing is finished, resume normal display
       
  2186 				 *  @method  _fnPrintEnd
       
  2187 				 *  @param   {Event} e Event object
       
  2188 				 *  @returns void
       
  2189 				 *  @private
       
  2190 				 */
       
  2191 				"_fnPrintEnd": function (e) {
       
  2192 					var that = this;
       
  2193 					var oSetDT = this.s.dt;
       
  2194 					var oSetPrint = this.s.print;
       
  2195 					var oDomPrint = this.dom.print;
       
  2196 
       
  2197 					/* Show all hidden nodes */
       
  2198 					this._fnPrintShowNodes();
       
  2199 
       
  2200 					/* Restore DataTables' scrolling */
       
  2201 					if (oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "") {
       
  2202 						$(this.s.dt.nTable).unbind('draw.DTTT_Print');
       
  2203 
       
  2204 						this._fnPrintScrollEnd();
       
  2205 					}
       
  2206 
       
  2207 					/* Restore the scroll */
       
  2208 					window.scrollTo(0, oSetPrint.saveScroll);
       
  2209 
       
  2210 					/* Drop the print message */
       
  2211 					if (oDomPrint.message !== null) {
       
  2212 						document.body.removeChild(oDomPrint.message);
       
  2213 						oDomPrint.message = null;
       
  2214 					}
       
  2215 
       
  2216 					/* Styling class */
       
  2217 					$(document.body).removeClass('DTTT_Print');
       
  2218 
       
  2219 					/* Restore the table length */
       
  2220 					oSetDT._iDisplayStart = oSetPrint.saveStart;
       
  2221 					oSetDT._iDisplayLength = oSetPrint.saveLength;
       
  2222 					if (oSetDT.oApi._fnCalculateEnd) {
       
  2223 						oSetDT.oApi._fnCalculateEnd(oSetDT);
       
  2224 					}
       
  2225 					oSetDT.oApi._fnDraw(oSetDT);
       
  2226 
       
  2227 					$(document).unbind("keydown.DTTT");
       
  2228 				},
       
  2229 
       
  2230 
       
  2231 				/**
       
  2232 				 * Take account of scrolling in DataTables by showing the full table
       
  2233 				 *  @returns void
       
  2234 				 *  @private
       
  2235 				 */
       
  2236 				"_fnPrintScrollStart": function () {
       
  2237 					var
       
  2238 						oSetDT = this.s.dt,
       
  2239 						nScrollHeadInner = oSetDT.nScrollHead.getElementsByTagName('div')[0],
       
  2240 						nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
       
  2241 						nScrollBody = oSetDT.nTable.parentNode,
       
  2242 						nTheadSize, nTfootSize;
       
  2243 
       
  2244 					/* Copy the header in the thead in the body table, this way we show one single table when
       
  2245 					 * in print view. Note that this section of code is more or less verbatim from DT 1.7.0
       
  2246 					 */
       
  2247 					nTheadSize = oSetDT.nTable.getElementsByTagName('thead');
       
  2248 					if (nTheadSize.length > 0) {
       
  2249 						oSetDT.nTable.removeChild(nTheadSize[0]);
       
  2250 					}
       
  2251 
       
  2252 					if (oSetDT.nTFoot !== null) {
       
  2253 						nTfootSize = oSetDT.nTable.getElementsByTagName('tfoot');
       
  2254 						if (nTfootSize.length > 0) {
       
  2255 							oSetDT.nTable.removeChild(nTfootSize[0]);
       
  2256 						}
       
  2257 					}
       
  2258 
       
  2259 					nTheadSize = oSetDT.nTHead.cloneNode(true);
       
  2260 					oSetDT.nTable.insertBefore(nTheadSize, oSetDT.nTable.childNodes[0]);
       
  2261 
       
  2262 					if (oSetDT.nTFoot !== null) {
       
  2263 						nTfootSize = oSetDT.nTFoot.cloneNode(true);
       
  2264 						oSetDT.nTable.insertBefore(nTfootSize, oSetDT.nTable.childNodes[1]);
       
  2265 					}
       
  2266 
       
  2267 					/* Now adjust the table's viewport so we can actually see it */
       
  2268 					if (oSetDT.oScroll.sX !== "") {
       
  2269 						oSetDT.nTable.style.width = $(oSetDT.nTable).outerWidth() + "px";
       
  2270 						nScrollBody.style.width = $(oSetDT.nTable).outerWidth() + "px";
       
  2271 						nScrollBody.style.overflow = "visible";
       
  2272 					}
       
  2273 
       
  2274 					if (oSetDT.oScroll.sY !== "") {
       
  2275 						nScrollBody.style.height = $(oSetDT.nTable).outerHeight() + "px";
       
  2276 						nScrollBody.style.overflow = "visible";
       
  2277 					}
       
  2278 				},
       
  2279 
       
  2280 
       
  2281 				/**
       
  2282 				 * Take account of scrolling in DataTables by showing the full table. Note that the redraw of
       
  2283 				 * the DataTable that we do will actually deal with the majority of the hard work here
       
  2284 				 *  @returns void
       
  2285 				 *  @private
       
  2286 				 */
       
  2287 				"_fnPrintScrollEnd": function () {
       
  2288 					var
       
  2289 						oSetDT = this.s.dt,
       
  2290 						nScrollBody = oSetDT.nTable.parentNode;
       
  2291 
       
  2292 					if (oSetDT.oScroll.sX !== "") {
       
  2293 						nScrollBody.style.width = oSetDT.oApi._fnStringToCss(oSetDT.oScroll.sX);
       
  2294 						nScrollBody.style.overflow = "auto";
       
  2295 					}
       
  2296 
       
  2297 					if (oSetDT.oScroll.sY !== "") {
       
  2298 						nScrollBody.style.height = oSetDT.oApi._fnStringToCss(oSetDT.oScroll.sY);
       
  2299 						nScrollBody.style.overflow = "auto";
       
  2300 					}
       
  2301 				},
       
  2302 
       
  2303 
       
  2304 				/**
       
  2305 				 * Resume the display of all TableTools hidden nodes
       
  2306 				 *  @method  _fnPrintShowNodes
       
  2307 				 *  @returns void
       
  2308 				 *  @private
       
  2309 				 */
       
  2310 				"_fnPrintShowNodes": function () {
       
  2311 					var anHidden = this.dom.print.hidden;
       
  2312 
       
  2313 					for (var i = 0, iLen = anHidden.length; i < iLen; i++) {
       
  2314 						anHidden[i].node.style.display = anHidden[i].display;
       
  2315 					}
       
  2316 					anHidden.splice(0, anHidden.length);
       
  2317 				},
       
  2318 
       
  2319 
       
  2320 				/**
       
  2321 				 * Hide nodes which are not needed in order to display the table. Note that this function is
       
  2322 				 * recursive
       
  2323 				 *  @method  _fnPrintHideNodes
       
  2324 				 *  @param   {Node} nNode Element which should be showing in a 'print' display
       
  2325 				 *  @returns void
       
  2326 				 *  @private
       
  2327 				 */
       
  2328 				"_fnPrintHideNodes": function (nNode) {
       
  2329 					var anHidden = this.dom.print.hidden;
       
  2330 
       
  2331 					var nParent = nNode.parentNode;
       
  2332 					var nChildren = nParent.childNodes;
       
  2333 					for (var i = 0, iLen = nChildren.length; i < iLen; i++) {
       
  2334 						if (nChildren[i] != nNode && nChildren[i].nodeType == 1) {
       
  2335 							/* If our node is shown (don't want to show nodes which were previously hidden) */
       
  2336 							var sDisplay = $(nChildren[i]).css("display");
       
  2337 							if (sDisplay != "none") {
       
  2338 								/* Cache the node and it's previous state so we can restore it */
       
  2339 								anHidden.push({
       
  2340 												  "node": nChildren[i],
       
  2341 												  "display": sDisplay
       
  2342 											  });
       
  2343 								nChildren[i].style.display = "none";
       
  2344 							}
       
  2345 						}
       
  2346 					}
       
  2347 
       
  2348 					if (nParent.nodeName.toUpperCase() != "BODY") {
       
  2349 						this._fnPrintHideNodes(nParent);
       
  2350 					}
       
  2351 				}
       
  2352 			};
       
  2353 
       
  2354 
       
  2355 			/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  2356 			 * Static variables
       
  2357 			 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  2358 
       
  2359 			/**
       
  2360 			 * Store of all instances that have been created of TableTools, so one can look up other (when
       
  2361 			 * there is need of a master)
       
  2362 			 *  @property _aInstances
       
  2363 			 *  @type     Array
       
  2364 			 *  @default  []
       
  2365 			 *  @private
       
  2366 			 */
       
  2367 			TableTools._aInstances = [];
       
  2368 
       
  2369 
       
  2370 			/**
       
  2371 			 * Store of all listeners and their callback functions
       
  2372 			 *  @property _aListeners
       
  2373 			 *  @type     Array
       
  2374 			 *  @default  []
       
  2375 			 */
       
  2376 			TableTools._aListeners = [];
       
  2377 
       
  2378 
       
  2379 			/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  2380 			 * Static methods
       
  2381 			 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  2382 
       
  2383 			/**
       
  2384 			 * Get an array of all the master instances
       
  2385 			 *  @method  fnGetMasters
       
  2386 			 *  @returns {Array} List of master TableTools instances
       
  2387 			 *  @static
       
  2388 			 */
       
  2389 			TableTools.fnGetMasters = function () {
       
  2390 				var a = [];
       
  2391 				for (var i = 0, iLen = TableTools._aInstances.length; i < iLen; i++) {
       
  2392 					if (TableTools._aInstances[i].s.master) {
       
  2393 						a.push(TableTools._aInstances[i]);
       
  2394 					}
       
  2395 				}
       
  2396 				return a;
       
  2397 			};
       
  2398 
       
  2399 			/**
       
  2400 			 * Get the master instance for a table node (or id if a string is given)
       
  2401 			 *  @method  fnGetInstance
       
  2402 			 *  @returns {Object} ID of table OR table node, for which we want the TableTools instance
       
  2403 			 *  @static
       
  2404 			 */
       
  2405 			TableTools.fnGetInstance = function (node) {
       
  2406 				if (typeof node != 'object') {
       
  2407 					node = document.getElementById(node);
       
  2408 				}
       
  2409 
       
  2410 				for (var i = 0, iLen = TableTools._aInstances.length; i < iLen; i++) {
       
  2411 					if (TableTools._aInstances[i].s.master && TableTools._aInstances[i].dom.table == node) {
       
  2412 						return TableTools._aInstances[i];
       
  2413 					}
       
  2414 				}
       
  2415 				return null;
       
  2416 			};
       
  2417 
       
  2418 
       
  2419 			/**
       
  2420 			 * Add a listener for a specific event
       
  2421 			 *  @method  _fnEventListen
       
  2422 			 *  @param   {Object} that Scope of the listening function (i.e. 'this' in the caller)
       
  2423 			 *  @param   {String} type Event type
       
  2424 			 *  @param   {Function} fn Function
       
  2425 			 *  @returns void
       
  2426 			 *  @private
       
  2427 			 *  @static
       
  2428 			 */
       
  2429 			TableTools._fnEventListen = function (that, type, fn) {
       
  2430 				TableTools._aListeners.push({
       
  2431 												"that": that,
       
  2432 												"type": type,
       
  2433 												"fn": fn
       
  2434 											});
       
  2435 			};
       
  2436 
       
  2437 
       
  2438 			/**
       
  2439 			 * An event has occurred - look up every listener and fire it off. We check that the event we are
       
  2440 			 * going to fire is attached to the same table (using the table node as reference) before firing
       
  2441 			 *  @method  _fnEventDispatch
       
  2442 			 *  @param   {Object} that Scope of the listening function (i.e. 'this' in the caller)
       
  2443 			 *  @param   {String} type Event type
       
  2444 			 *  @param   {Node} node Element that the event occurred on (may be null)
       
  2445 			 *  @param   {boolean} [selected] Indicate if the node was selected (true) or deselected (false)
       
  2446 			 *  @returns void
       
  2447 			 *  @private
       
  2448 			 *  @static
       
  2449 			 */
       
  2450 			TableTools._fnEventDispatch = function (that, type, node, selected) {
       
  2451 				var listeners = TableTools._aListeners;
       
  2452 				for (var i = 0, iLen = listeners.length; i < iLen; i++) {
       
  2453 					if (that.dom.table == listeners[i].that.dom.table && listeners[i].type == type) {
       
  2454 						listeners[i].fn(node, selected);
       
  2455 					}
       
  2456 				}
       
  2457 			};
       
  2458 
       
  2459 
       
  2460 			/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  2461 			 * Constants
       
  2462 			 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  2463 
       
  2464 
       
  2465 			TableTools.buttonBase = {
       
  2466 				// Button base
       
  2467 				"sAction": "text",
       
  2468 				"sTag": "default",
       
  2469 				"sLinerTag": "default",
       
  2470 				"sButtonClass": "DTTT_button_text",
       
  2471 				"sButtonText": "Button text",
       
  2472 				"sTitle": "",
       
  2473 				"sToolTip": "",
       
  2474 
       
  2475 				// Common button specific options
       
  2476 				"sCharSet": "utf8",
       
  2477 				"bBomInc": false,
       
  2478 				"sFileName": "*.csv",
       
  2479 				"sFieldBoundary": "",
       
  2480 				"sFieldSeperator": "\t",
       
  2481 				"sNewLine": "auto",
       
  2482 				"mColumns": "all", /* "all", "visible", "hidden" or array of column integers */
       
  2483 				"bHeader": true,
       
  2484 				"bFooter": true,
       
  2485 				"bOpenRows": false,
       
  2486 				"bSelectedOnly": false,
       
  2487 				"oSelectorOpts": undefined, // See http://datatables.net/docs/DataTables/1.9.4/#$ for full options
       
  2488 
       
  2489 				// Callbacks
       
  2490 				"fnMouseover": null,
       
  2491 				"fnMouseout": null,
       
  2492 				"fnClick": null,
       
  2493 				"fnSelect": null,
       
  2494 				"fnComplete": null,
       
  2495 				"fnInit": null,
       
  2496 				"fnCellRender": null
       
  2497 			};
       
  2498 
       
  2499 
       
  2500 			/**
       
  2501 			 * @namespace Default button configurations
       
  2502 			 */
       
  2503 			TableTools.BUTTONS = {
       
  2504 				"csv": $.extend({}, TableTools.buttonBase, {
       
  2505 					"sAction": "flash_save",
       
  2506 					"sButtonClass": "DTTT_button_csv",
       
  2507 					"sButtonText": "CSV",
       
  2508 					"sFieldBoundary": '"',
       
  2509 					"sFieldSeperator": ",",
       
  2510 					"fnClick": function (nButton, oConfig, flash) {
       
  2511 						this.fnSetText(flash, this.fnGetTableData(oConfig));
       
  2512 					}
       
  2513 				}),
       
  2514 
       
  2515 				"xls": $.extend({}, TableTools.buttonBase, {
       
  2516 					"sAction": "flash_save",
       
  2517 					"sCharSet": "utf16le",
       
  2518 					"bBomInc": true,
       
  2519 					"sButtonClass": "DTTT_button_xls",
       
  2520 					"sButtonText": "Excel",
       
  2521 					"fnClick": function (nButton, oConfig, flash) {
       
  2522 						this.fnSetText(flash, this.fnGetTableData(oConfig));
       
  2523 					}
       
  2524 				}),
       
  2525 
       
  2526 				"copy": $.extend({}, TableTools.buttonBase, {
       
  2527 					"sAction": "flash_copy",
       
  2528 					"sButtonClass": "DTTT_button_copy",
       
  2529 					"sButtonText": "Copy",
       
  2530 					"fnClick": function (nButton, oConfig, flash) {
       
  2531 						this.fnSetText(flash, this.fnGetTableData(oConfig));
       
  2532 					},
       
  2533 					"fnComplete": function (nButton, oConfig, flash, text) {
       
  2534 						var
       
  2535 							lines = text.split('\n').length,
       
  2536 							len = this.s.dt.nTFoot === null ? lines - 1 : lines - 2,
       
  2537 							plural = (len == 1) ? "" : "s";
       
  2538 						this.fnInfo('<h6>Table copied</h6>' +
       
  2539 										'<p>Copied ' + len + ' row' + plural + ' to the clipboard.</p>',
       
  2540 									1500
       
  2541 						);
       
  2542 					}
       
  2543 				}),
       
  2544 
       
  2545 				"pdf": $.extend({}, TableTools.buttonBase, {
       
  2546 					"sAction": "flash_pdf",
       
  2547 					"sNewLine": "\n",
       
  2548 					"sFileName": "*.pdf",
       
  2549 					"sButtonClass": "DTTT_button_pdf",
       
  2550 					"sButtonText": "PDF",
       
  2551 					"sPdfOrientation": "portrait",
       
  2552 					"sPdfSize": "A4",
       
  2553 					"sPdfMessage": "",
       
  2554 					"fnClick": function (nButton, oConfig, flash) {
       
  2555 						this.fnSetText(flash,
       
  2556 									   "title:" + this.fnGetTitle(oConfig) + "\n" +
       
  2557 										   "message:" + oConfig.sPdfMessage + "\n" +
       
  2558 										   "colWidth:" + this.fnCalcColRatios(oConfig) + "\n" +
       
  2559 										   "orientation:" + oConfig.sPdfOrientation + "\n" +
       
  2560 										   "size:" + oConfig.sPdfSize + "\n" +
       
  2561 										   "--/TableToolsOpts--\n" +
       
  2562 										   this.fnGetTableData(oConfig)
       
  2563 						);
       
  2564 					}
       
  2565 				}),
       
  2566 
       
  2567 				"print": $.extend({}, TableTools.buttonBase, {
       
  2568 					"sInfo": "<h6>Print view</h6><p>Please use your browser's print function to " +
       
  2569 						"print this table. Press escape when finished.</p>",
       
  2570 					"sMessage": null,
       
  2571 					"bShowAll": true,
       
  2572 					"sToolTip": "View print view",
       
  2573 					"sButtonClass": "DTTT_button_print",
       
  2574 					"sButtonText": "Print",
       
  2575 					"fnClick": function (nButton, oConfig) {
       
  2576 						this.fnPrint(true, oConfig);
       
  2577 					}
       
  2578 				}),
       
  2579 
       
  2580 				"text": $.extend({}, TableTools.buttonBase),
       
  2581 
       
  2582 				"select": $.extend({}, TableTools.buttonBase, {
       
  2583 					"sButtonText": "Select button",
       
  2584 					"fnSelect": function (nButton, oConfig) {
       
  2585 						if (this.fnGetSelected().length !== 0) {
       
  2586 							$(nButton).removeClass(this.classes.buttons.disabled);
       
  2587 						} else {
       
  2588 							$(nButton).addClass(this.classes.buttons.disabled);
       
  2589 						}
       
  2590 					},
       
  2591 					"fnInit": function (nButton, oConfig) {
       
  2592 						$(nButton).addClass(this.classes.buttons.disabled);
       
  2593 					}
       
  2594 				}),
       
  2595 
       
  2596 				"select_single": $.extend({}, TableTools.buttonBase, {
       
  2597 					"sButtonText": "Select button",
       
  2598 					"fnSelect": function (nButton, oConfig) {
       
  2599 						var iSelected = this.fnGetSelected().length;
       
  2600 						if (iSelected == 1) {
       
  2601 							$(nButton).removeClass(this.classes.buttons.disabled);
       
  2602 						} else {
       
  2603 							$(nButton).addClass(this.classes.buttons.disabled);
       
  2604 						}
       
  2605 					},
       
  2606 					"fnInit": function (nButton, oConfig) {
       
  2607 						$(nButton).addClass(this.classes.buttons.disabled);
       
  2608 					}
       
  2609 				}),
       
  2610 
       
  2611 				"select_all": $.extend({}, TableTools.buttonBase, {
       
  2612 					"sButtonText": "Select all",
       
  2613 					"fnClick": function (nButton, oConfig) {
       
  2614 						this.fnSelectAll();
       
  2615 					},
       
  2616 					"fnSelect": function (nButton, oConfig) {
       
  2617 						if (this.fnGetSelected().length == this.s.dt.fnRecordsDisplay()) {
       
  2618 							$(nButton).addClass(this.classes.buttons.disabled);
       
  2619 						} else {
       
  2620 							$(nButton).removeClass(this.classes.buttons.disabled);
       
  2621 						}
       
  2622 					}
       
  2623 				}),
       
  2624 
       
  2625 				"select_none": $.extend({}, TableTools.buttonBase, {
       
  2626 					"sButtonText": "Deselect all",
       
  2627 					"fnClick": function (nButton, oConfig) {
       
  2628 						this.fnSelectNone();
       
  2629 					},
       
  2630 					"fnSelect": function (nButton, oConfig) {
       
  2631 						if (this.fnGetSelected().length !== 0) {
       
  2632 							$(nButton).removeClass(this.classes.buttons.disabled);
       
  2633 						} else {
       
  2634 							$(nButton).addClass(this.classes.buttons.disabled);
       
  2635 						}
       
  2636 					},
       
  2637 					"fnInit": function (nButton, oConfig) {
       
  2638 						$(nButton).addClass(this.classes.buttons.disabled);
       
  2639 					}
       
  2640 				}),
       
  2641 
       
  2642 				"ajax": $.extend({}, TableTools.buttonBase, {
       
  2643 					"sAjaxUrl": "/xhr.php",
       
  2644 					"sButtonText": "Ajax button",
       
  2645 					"fnClick": function (nButton, oConfig) {
       
  2646 						var sData = this.fnGetTableData(oConfig);
       
  2647 						$.ajax({
       
  2648 								   "url": oConfig.sAjaxUrl,
       
  2649 								   "data": [
       
  2650 									   { "name": "tableData", "value": sData }
       
  2651 								   ],
       
  2652 								   "success": oConfig.fnAjaxComplete,
       
  2653 								   "dataType": "json",
       
  2654 								   "type": "POST",
       
  2655 								   "cache": false,
       
  2656 								   "error": function () {
       
  2657 									   alert("Error detected when sending table data to server");
       
  2658 								   }
       
  2659 							   });
       
  2660 					},
       
  2661 					"fnAjaxComplete": function (json) {
       
  2662 						alert('Ajax complete');
       
  2663 					}
       
  2664 				}),
       
  2665 
       
  2666 				"div": $.extend({}, TableTools.buttonBase, {
       
  2667 					"sAction": "div",
       
  2668 					"sTag": "div",
       
  2669 					"sButtonClass": "DTTT_nonbutton",
       
  2670 					"sButtonText": "Text button"
       
  2671 				}),
       
  2672 
       
  2673 				"collection": $.extend({}, TableTools.buttonBase, {
       
  2674 					"sAction": "collection",
       
  2675 					"sButtonClass": "DTTT_button_collection",
       
  2676 					"sButtonText": "Collection",
       
  2677 					"fnClick": function (nButton, oConfig) {
       
  2678 						this._fnCollectionShow(nButton, oConfig);
       
  2679 					}
       
  2680 				})
       
  2681 			};
       
  2682 			/*
       
  2683 			 *  on* callback parameters:
       
  2684 			 *     1. node - button element
       
  2685 			 *     2. object - configuration object for this button
       
  2686 			 *     3. object - ZeroClipboard reference (flash button only)
       
  2687 			 *     4. string - Returned string from Flash (flash button only - and only on 'complete')
       
  2688 			 */
       
  2689 
       
  2690 // Alias to match the other plug-ins styling
       
  2691 			TableTools.buttons = TableTools.BUTTONS;
       
  2692 
       
  2693 
       
  2694 			/**
       
  2695 			 * @namespace Classes used by TableTools - allows the styles to be override easily.
       
  2696 			 *   Note that when TableTools initialises it will take a copy of the classes object
       
  2697 			 *   and will use its internal copy for the remainder of its run time.
       
  2698 			 */
       
  2699 			TableTools.classes = {
       
  2700 				"container": "DTTT_container",
       
  2701 				"buttons": {
       
  2702 					"normal": "DTTT_button",
       
  2703 					"disabled": "DTTT_disabled"
       
  2704 				},
       
  2705 				"collection": {
       
  2706 					"container": "DTTT_collection",
       
  2707 					"background": "DTTT_collection_background",
       
  2708 					"buttons": {
       
  2709 						"normal": "DTTT_button",
       
  2710 						"disabled": "DTTT_disabled"
       
  2711 					}
       
  2712 				},
       
  2713 				"select": {
       
  2714 					"table": "DTTT_selectable",
       
  2715 					"row": "DTTT_selected selected"
       
  2716 				},
       
  2717 				"print": {
       
  2718 					"body": "DTTT_Print",
       
  2719 					"info": "DTTT_print_info",
       
  2720 					"message": "DTTT_PrintMessage"
       
  2721 				}
       
  2722 			};
       
  2723 
       
  2724 
       
  2725 			/**
       
  2726 			 * @namespace ThemeRoller classes - built in for compatibility with DataTables'
       
  2727 			 *   bJQueryUI option.
       
  2728 			 */
       
  2729 			TableTools.classes_themeroller = {
       
  2730 				"container": "DTTT_container ui-buttonset ui-buttonset-multi",
       
  2731 				"buttons": {
       
  2732 					"normal": "DTTT_button ui-button ui-state-default"
       
  2733 				},
       
  2734 				"collection": {
       
  2735 					"container": "DTTT_collection ui-buttonset ui-buttonset-multi"
       
  2736 				}
       
  2737 			};
       
  2738 
       
  2739 
       
  2740 			/**
       
  2741 			 * @namespace TableTools default settings for initialisation
       
  2742 			 */
       
  2743 			TableTools.DEFAULTS = {
       
  2744 				"sSwfPath": "../swf/copy_csv_xls_pdf.swf",
       
  2745 				"sRowSelect": "none",
       
  2746 				"sSelectedClass": null,
       
  2747 				"fnPreRowSelect": null,
       
  2748 				"fnRowSelected": null,
       
  2749 				"fnRowDeselected": null,
       
  2750 				"aButtons": [ "copy", "csv", "xls", "pdf", "print" ],
       
  2751 				"oTags": {
       
  2752 					"container": "div",
       
  2753 					"button": "a", // We really want to use buttons here, but Firefox and IE ignore the
       
  2754 					// click on the Flash element in the button (but not mouse[in|out]).
       
  2755 					"liner": "span",
       
  2756 					"collection": {
       
  2757 						"container": "div",
       
  2758 						"button": "a",
       
  2759 						"liner": "span"
       
  2760 					}
       
  2761 				}
       
  2762 			};
       
  2763 
       
  2764 // Alias to match the other plug-ins
       
  2765 			TableTools.defaults = TableTools.DEFAULTS;
       
  2766 
       
  2767 
       
  2768 			/**
       
  2769 			 * Name of this class
       
  2770 			 *  @constant CLASS
       
  2771 			 *  @type     String
       
  2772 			 *  @default  TableTools
       
  2773 			 */
       
  2774 			TableTools.prototype.CLASS = "TableTools";
       
  2775 
       
  2776 
       
  2777 			/**
       
  2778 			 * TableTools version
       
  2779 			 *  @constant  VERSION
       
  2780 			 *  @type      String
       
  2781 			 *  @default   See code
       
  2782 			 */
       
  2783 			TableTools.version = "2.2.0-dev";
       
  2784 
       
  2785 
       
  2786 // DataTables 1.10 API
       
  2787 // 
       
  2788 // This will be extended in a big way in in TableTools 3 to provide API methods
       
  2789 // such as rows().select() and rows.selected() etc, but for the moment the
       
  2790 // tabletools() method simply returns the instance.
       
  2791 
       
  2792 			if ($.fn.dataTable.Api) {
       
  2793 				$.fn.dataTable.Api.register('tabletools()', function () {
       
  2794 					var tt = null;
       
  2795 
       
  2796 					if (this.context.length > 0) {
       
  2797 						tt = TableTools.fnGetInstance(this.context[0].nTable);
       
  2798 					}
       
  2799 
       
  2800 					return tt;
       
  2801 				});
       
  2802 			}
       
  2803 
       
  2804 
       
  2805 			/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
       
  2806 			 * Initialisation
       
  2807 			 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
       
  2808 
       
  2809 			/*
       
  2810 			 * Register a new feature with DataTables
       
  2811 			 */
       
  2812 			if (typeof $.fn.dataTable == "function" &&
       
  2813 				typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
       
  2814 				$.fn.dataTableExt.fnVersionCheck('1.9.0')) {
       
  2815 				$.fn.dataTableExt.aoFeatures.push({
       
  2816 													  "fnInit": function (oDTSettings) {
       
  2817 														  var init = oDTSettings.oInit;
       
  2818 														  var opts = init.tableTools || init.oTableTools || {};
       
  2819 
       
  2820 														  var oTT = new TableTools(oDTSettings.oInstance, opts);
       
  2821 														  TableTools._aInstances.push(oTT);
       
  2822 
       
  2823 														  return oTT.dom.container;
       
  2824 													  },
       
  2825 													  "cFeature": "T",
       
  2826 													  "sFeature": "TableTools"
       
  2827 												  });
       
  2828 			}
       
  2829 			else {
       
  2830 				alert("Warning: TableTools requires DataTables 1.9.0 or newer - www.datatables.net/download");
       
  2831 			}
       
  2832 
       
  2833 			$.fn.DataTable.TableTools = TableTools;
       
  2834 
       
  2835 		})(jQuery, window, document);
       
  2836 
       
  2837 		/*
       
  2838 		 * Register a new feature with DataTables
       
  2839 		 */
       
  2840 		if (typeof $.fn.dataTable == "function" &&
       
  2841 			typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
       
  2842 			$.fn.dataTableExt.fnVersionCheck('1.9.0')) {
       
  2843 			$.fn.dataTableExt.aoFeatures.push({
       
  2844 												  "fnInit": function (oDTSettings) {
       
  2845 													  var oOpts = typeof oDTSettings.oInit.oTableTools != 'undefined' ?
       
  2846 														  oDTSettings.oInit.oTableTools : {};
       
  2847 
       
  2848 													  var oTT = new TableTools(oDTSettings.oInstance, oOpts);
       
  2849 													  TableTools._aInstances.push(oTT);
       
  2850 
       
  2851 													  return oTT.dom.container;
       
  2852 												  },
       
  2853 												  "cFeature": "T",
       
  2854 												  "sFeature": "TableTools"
       
  2855 											  });
       
  2856 		}
       
  2857 		else {
       
  2858 			alert("Warning: TableTools 2 requires DataTables 1.9.0 or newer - www.datatables.net/download");
       
  2859 		}
       
  2860 
       
  2861 
       
  2862 		$.fn.dataTable.TableTools = TableTools;
       
  2863 		$.fn.DataTable.TableTools = TableTools;
       
  2864 
       
  2865 
       
  2866 		return TableTools;
       
  2867 	}; // /factory
       
  2868 
       
  2869 
       
  2870 	factory(jQuery, jQuery.fn.dataTable);
       
  2871 
       
  2872 
       
  2873 })(window, document);
       
  2874