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