1 /* 2 * File: TableTools.js 3 * Version: 2.0.1 4 * Description: Tools and buttons for DataTables 5 * Author: Allan Jardine (www.sprymedia.co.uk) 6 * Language: Javascript 7 * License: LGPL / 3 point BSD 8 * Project: DataTables 9 * 10 * Copyright 2009-2011 Allan Jardine, all rights reserved. 11 */ 12 13 /* Global scope for TableTools */ 14 var TableTools; 15 16 (function($, window, document) { 17 18 /** 19 * TableTools provides flexible buttons and other tools for a DataTables enhanced table 20 * @class TableTools 21 * @constructor 22 * @param {Object} oDT DataTables instance 23 * @param {Object} oOpts TableTools options 24 * @param {String} oOpts.sSwfPath ZeroClipboard SWF path 25 * @param {String} oOpts.sRowSelect Row selection options - 'none', 'single' or 'multi' 26 * @param {Function} oOpts.fnPreRowSelect Callback function just prior to row selection 27 * @param {Function} oOpts.fnRowSelected Callback function just after row selection 28 * @param {Function} oOpts.fnRowDeselected Callback function when row is deselected 29 * @param {Array} oOpts.aButtons List of buttons to be used 30 */ 31 TableTools = function( oDT, oOpts ) 32 { 33 /* Santiy check that we are a new instance */ 34 if ( !this.CLASS || this.CLASS != "TableTools" ) 35 { 36 alert( "Warning: TableTools must be initialised with the keyword 'new'" ); 37 } 38 39 40 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 41 * Public class variables 42 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 43 44 /** 45 * @namespace Settings object which contains customisable information for TableTools instance 46 */ 47 this.s = { 48 /** 49 * Store 'this' so the instance can be retreieved from the settings object 50 * @property that 51 * @type object 52 * @default this 53 */ 54 that: this, 55 56 /** 57 * DataTables settings objects 58 * @property dt 59 * @type object 60 * @default null 61 */ 62 dt: null, 63 64 /** 65 * @namespace Print specific information 66 */ 67 print: { 68 /** 69 * DataTables draw 'start' point before the printing display was shown 70 * @property saveStart 71 * @type int 72 * @default -1 73 */ 74 saveStart: -1, 75 76 /** 77 * DataTables draw 'length' point before the printing display was shown 78 * @property saveLength 79 * @type int 80 * @default -1 81 */ 82 saveLength: -1, 83 84 /** 85 * Page scrolling point before the printing display was shown so it can be restored 86 * @property saveScroll 87 * @type int 88 * @default -1 89 */ 90 saveScroll: -1, 91 92 /** 93 * Wrapped function to end the print display (to maintain scope) 94 * @property funcEnd 95 * @type Function 96 * @default function () {} 97 */ 98 funcEnd: function () {} 99 }, 100 101 /** 102 * A unique ID is assigned to each button in each instance 103 * @property buttonCounter 104 * @type int 105 * @default 0 106 */ 107 buttonCounter: 0, 108 109 /** 110 * @namespace Select rows specific information 111 */ 112 select: { 113 /** 114 * Select type - can be 'none', 'single' or 'multi' 115 * @property type 116 * @type string 117 * @default "" 118 */ 119 type: "", 120 121 /** 122 * Array of nodes which are currently selected 123 * @property selected 124 * @type array 125 * @default [] 126 */ 127 selected: [], 128 129 /** 130 * Function to run before the selection can take place. Will cancel the select if the 131 * function returns false 132 * @property preRowSelect 133 * @type Function 134 * @default null 135 */ 136 preRowSelect: null, 137 138 /** 139 * Function to run when a row is selected 140 * @property postSelected 141 * @type Function 142 * @default null 143 */ 144 postSelected: null, 145 146 /** 147 * Function to run when a row is deselected 148 * @property postDeselected 149 * @type Function 150 * @default null 151 */ 152 postDeselected: null, 153 154 /** 155 * Indicate if all rows are selected (needed for server-side processing) 156 * @property all 157 * @type boolean 158 * @default false 159 */ 160 all: false, 161 162 /** 163 * Class name to add to selected TR nodes 164 * @property selectedClass 165 * @type String 166 * @default "" 167 */ 168 selectedClass: "" 169 }, 170 171 /** 172 * Store of the user input customisation object 173 * @property custom 174 * @type object 175 * @default {} 176 */ 177 custom: {}, 178 179 /** 180 * SWF movie path 181 * @property swfPath 182 * @type string 183 * @default "" 184 */ 185 swfPath: "", 186 187 /** 188 * Default button set 189 * @property buttonSet 190 * @type array 191 * @default [] 192 */ 193 buttonSet: [], 194 195 /** 196 * When there is more than one TableTools instance for a DataTable, there must be a 197 * master which controls events (row selection etc) 198 * @property master 199 * @type boolean 200 * @default false 201 */ 202 master: false 203 }; 204 205 206 /** 207 * @namespace Common and useful DOM elements for the class instance 208 */ 209 this.dom = { 210 /** 211 * DIV element that is create and all TableTools buttons (and their children) put into 212 * @property container 213 * @type node 214 * @default null 215 */ 216 container: null, 217 218 /** 219 * The table node to which TableTools will be applied 220 * @property table 221 * @type node 222 * @default null 223 */ 224 table: null, 225 226 /** 227 * @namespace Nodes used for the print display 228 */ 229 print: { 230 /** 231 * Nodes which have been removed from the display by setting them to display none 232 * @property hidden 233 * @type array 234 * @default [] 235 */ 236 hidden: [], 237 238 /** 239 * The information display saying tellng the user about the print display 240 * @property message 241 * @type node 242 * @default null 243 */ 244 message: null 245 }, 246 247 /** 248 * @namespace Nodes used for a collection display. This contains the currently used collection 249 */ 250 collection: { 251 /** 252 * The div wrapper containing the buttons in the collection (i.e. the menu) 253 * @property collection 254 * @type node 255 * @default null 256 */ 257 collection: null, 258 259 /** 260 * Background display to provide focus and capture events 261 * @property background 262 * @type node 263 * @default null 264 */ 265 background: null 266 } 267 }; 268 269 270 271 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 272 * Public class methods 273 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 274 275 /** 276 * Retreieve the settings object from an instance 277 * @method fnSettings 278 * @returns {object} TableTools settings object 279 */ 280 this.fnSettings = function () { 281 return this.s; 282 }; 283 284 285 /* Constructor logic */ 286 if ( typeof oOpts == 'undefined' ) 287 { 288 oOpts = {}; 289 } 290 291 this.s.dt = oDT.fnSettings(); 292 this._fnConstruct( oOpts ); 293 294 return this; 295 }; 296 297 298 299 TableTools.prototype = { 300 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 301 * Public methods 302 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 303 304 /** 305 * Retreieve the settings object from an instance 306 * @method fnGetSelected 307 * @returns {array} List of TR nodes which are currently selected 308 */ 309 fnGetSelected: function () 310 { 311 var masterS = this._fnGetMasterSettings(); 312 return masterS.select.selected; 313 }, 314 315 /** 316 * Check to see if a current row is selected or not 317 * @method fnGetSelected 318 * @param {Node} n TR node to check if it is currently selected or not 319 * @returns {Boolean} true if select, false otherwise 320 */ 321 fnIsSelected: function ( n ) 322 { 323 var selected = this.fnGetSelected(); 324 for ( var i=0, iLen=selected.length ; i<iLen ; i++ ) 325 { 326 if ( n == selected[i] ) 327 { 328 return true; 329 } 330 } 331 return false; 332 }, 333 334 /** 335 * Select all rows in the table 336 * @method fnSelectAll 337 * @returns void 338 */ 339 fnSelectAll: function () 340 { 341 var masterS = this._fnGetMasterSettings(); 342 masterS.that._fnRowSelectAll(); 343 }, 344 345 346 /** 347 * Deselect all rows in the table 348 * @method fnSelectNone 349 * @returns void 350 */ 351 fnSelectNone: function () 352 { 353 var masterS = this._fnGetMasterSettings(); 354 masterS.that._fnRowDeselectAll(); 355 }, 356 357 358 /** 359 * Get the title of the document - useful for file names. The title is retrieved from either 360 * the configuration object's 'title' parameter, or the HTML document title 361 * @method fnGetTitle 362 * @param {Object} oConfig Button configuration object 363 * @returns {String} Button title 364 */ 365 fnGetTitle: function( oConfig ) 366 { 367 var sTitle = ""; 368 if ( typeof oConfig.sTitle != 'undefined' && oConfig.sTitle !== "" ) { 369 sTitle = oConfig.sTitle; 370 } else { 371 var anTitle = document.getElementsByTagName('title'); 372 if ( anTitle.length > 0 ) 373 { 374 sTitle = anTitle[0].innerHTML; 375 } 376 } 377 378 /* Strip characters which the OS will object to - checking for UTF8 support in the scripting 379 * engine 380 */ 381 if ( "\u00A1".toString().length < 4 ) { 382 return sTitle.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, ""); 383 } else { 384 return sTitle.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g, ""); 385 } 386 }, 387 388 389 /** 390 * Calculate a unity array with the column width by proportion for a set of columns to be 391 * included for a button. This is particularly useful for PDF creation, where we can use the 392 * column widths calculated by the browser to size the columns in the PDF. 393 * @method fnCalcColRations 394 * @param {Object} oConfig Button configuration object 395 * @returns {Array} Unity array of column ratios 396 */ 397 fnCalcColRatios: function ( oConfig ) 398 { 399 var 400 aoCols = this.s.dt.aoColumns, 401 aColumnsInc = this._fnColumnTargets( oConfig.mColumns ), 402 aColWidths = [], 403 iWidth = 0, iTotal = 0, i, iLen; 404 405 for ( i=0, iLen=aColumnsInc.length ; i<iLen ; i++ ) 406 { 407 if ( aColumnsInc[i] ) 408 { 409 iWidth = aoCols[i].nTh.offsetWidth; 410 iTotal += iWidth; 411 aColWidths.push( iWidth ); 412 } 413 } 414 415 for ( i=0, iLen=aColWidths.length ; i<iLen ; i++ ) 416 { 417 aColWidths[i] = aColWidths[i] / iTotal; 418 } 419 420 return aColWidths.join('\t'); 421 }, 422 423 424 /** 425 * Get the information contained in a table as a string 426 * @method fnGetTableData 427 * @param {Object} oConfig Button configuration object 428 * @returns {String} Table data as a string 429 */ 430 fnGetTableData: function ( oConfig ) 431 { 432 /* In future this could be used to get data from a plain HTML source as well as DataTables */ 433 if ( this.s.dt ) 434 { 435 return this._fnGetDataTablesData( oConfig ); 436 } 437 }, 438 439 440 /** 441 * Pass text to a flash button instance, which will be used on the button's click handler 442 * @method fnSetText 443 * @param {Object} clip Flash button object 444 * @param {String} text Text to set 445 * @returns void 446 */ 447 fnSetText: function ( clip, text ) 448 { 449 this._fnFlashSetText( clip, text ); 450 }, 451 452 453 /** 454 * Resize the flash elements of the buttons attached to this TableTools instance - this is 455 * useful for when initialising TableTools when it is hidden (display:none) since sizes can't 456 * be calculated at that time. 457 * @method fnResizeButtons 458 * @returns void 459 */ 460 fnResizeButtons: function () 461 { 462 for ( var cli in ZeroClipboard.clients ) 463 { 464 if ( cli ) 465 { 466 var client = ZeroClipboard.clients[cli]; 467 if ( typeof client.domElement != 'undefined' && 468 client.domElement.parentNode == this.dom.container ) 469 { 470 client.positionElement(); 471 } 472 } 473 } 474 }, 475 476 477 /** 478 * Check to see if any of the ZeroClipboard client's attached need to be resized 479 * @method fnResizeRequired 480 * @returns void 481 */ 482 fnResizeRequired: function () 483 { 484 for ( var cli in ZeroClipboard.clients ) 485 { 486 if ( cli ) 487 { 488 var client = ZeroClipboard.clients[cli]; 489 if ( typeof client.domElement != 'undefined' && 490 client.domElement.parentNode == this.dom.container && 491 client.sized === false ) 492 { 493 return true; 494 } 495 } 496 } 497 return false; 498 }, 499 500 501 502 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 503 * Private methods (they are of course public in JS, but recommended as private) 504 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 505 506 /** 507 * Constructor logic 508 * @method _fnConstruct 509 * @param {Object} oOpts Same as TableTools constructor 510 * @returns void 511 * @private 512 */ 513 _fnConstruct: function ( oOpts ) 514 { 515 this._fnCustomiseSettings( oOpts ); 516 517 /* Container element */ 518 this.dom.container = document.createElement('div'); 519 this.dom.container.style.position = "relative"; 520 this.dom.container.className = !this.s.dt.bJUI ? "DTTT_container" : 521 "DTTT_container ui-buttonset ui-buttonset-multi"; 522 523 /* Row selection config */ 524 if ( this.s.select.type != 'none' ) 525 { 526 this._fnRowSelectConfig(); 527 } 528 529 /* Buttons */ 530 this._fnButtonDefinations( this.s.buttonSet, this.dom.container ); 531 }, 532 533 534 /** 535 * Take the user defined settings and the default settings and combine them. 536 * @method _fnCustomiseSettings 537 * @param {Object} oOpts Same as TableTools constructor 538 * @returns void 539 * @private 540 */ 541 _fnCustomiseSettings: function ( oOpts ) 542 { 543 /* Is this the master control instance or not? */ 544 if ( typeof this.s.dt._TableToolsInit == 'undefined' ) 545 { 546 this.s.master = true; 547 this.s.dt._TableToolsInit = true; 548 } 549 550 /* We can use the table node from comparisons to group controls */ 551 this.dom.table = this.s.dt.nTable; 552 553 /* Clone the defaults and then the user options */ 554 this.s.custom = $.extend( {}, TableTools.DEFAULTS, oOpts ); 555 556 /* Flash file location */ 557 this.s.swfPath = this.s.custom.sSwfPath; 558 if ( typeof ZeroClipboard != 'undefined' ) 559 { 560 ZeroClipboard.moviePath = this.s.swfPath; 561 } 562 563 /* Table row selecting */ 564 this.s.select.type = this.s.custom.sRowSelect; 565 this.s.select.preRowSelect = this.s.custom.fnPreRowSelect; 566 this.s.select.postSelected = this.s.custom.fnRowSelected; 567 this.s.select.postDeselected = this.s.custom.fnRowDeselected; 568 this.s.select.selectedClass = this.s.custom.sSelectedClass; 569 570 /* Button set */ 571 this.s.buttonSet = this.s.custom.aButtons; 572 }, 573 574 575 /** 576 * Take the user input arrays and expand them to be fully defined, and then add them to a given 577 * DOM element 578 * @method _fnButtonDefinations 579 * @param {array} buttonSet Set of user defined buttons 580 * @param {node} wrapper Node to add the created buttons to 581 * @returns void 582 * @private 583 */ 584 _fnButtonDefinations: function ( buttonSet, wrapper ) 585 { 586 var buttonDef; 587 588 for ( var i=0, iLen=buttonSet.length ; i<iLen ; i++ ) 589 { 590 if ( typeof buttonSet[i] == "string" ) 591 { 592 if ( typeof TableTools.BUTTONS[ buttonSet[i] ] == 'undefined' ) 593 { 594 alert( "TableTools: Warning - unknown button type: "+buttonSet[i] ); 595 continue; 596 } 597 buttonDef = $.extend( {}, TableTools.BUTTONS[ buttonSet[i] ], true ); 598 } 599 else 600 { 601 if ( typeof TableTools.BUTTONS[ buttonSet[i].sExtends ] == 'undefined' ) 602 { 603 alert( "TableTools: Warning - unknown button type: "+buttonSet[i].sExtends ); 604 continue; 605 } 606 var o = $.extend( {}, TableTools.BUTTONS[ buttonSet[i].sExtends ], true ); 607 buttonDef = $.extend( o, buttonSet[i], true ); 608 } 609 610 if ( this.s.dt.bJUI ) 611 { 612 buttonDef.sButtonClass += " ui-button ui-state-default"; 613 buttonDef.sButtonClassHover += " ui-button ui-state-default ui-state-hover"; 614 } 615 616 wrapper.appendChild( this._fnCreateButton( buttonDef ) ); 617 } 618 }, 619 620 621 /** 622 * Create and configure a TableTools button 623 * @method _fnCreateButton 624 * @param {Object} oConfig Button configuration object 625 * @returns {Node} Button element 626 * @private 627 */ 628 _fnCreateButton: function ( oConfig ) 629 { 630 var nButton = this._fnButtonBase( oConfig ); 631 632 if ( oConfig.sAction == "print" ) 633 { 634 this._fnPrintConfig( nButton, oConfig ); 635 } 636 else if ( oConfig.sAction.match(/flash/) ) 637 { 638 this._fnFlashConfig( nButton, oConfig ); 639 } 640 else if ( oConfig.sAction == "text" ) 641 { 642 this._fnTextConfig( nButton, oConfig ); 643 } 644 else if ( oConfig.sAction == "collection" ) 645 { 646 this._fnTextConfig( nButton, oConfig ); 647 this._fnCollectionConfig( nButton, oConfig ); 648 } 649 650 return nButton; 651 }, 652 653 654 /** 655 * Create the DOM needed for the button and apply some base properties. All buttons start here 656 * @method _fnButtonBase 657 * @param {o} oConfig Button configuration object 658 * @returns {Node} DIV element for the button 659 * @private 660 */ 661 _fnButtonBase: function ( o ) 662 { 663 var 664 nButton = document.createElement('button'), 665 nSpan = document.createElement('span'), 666 masterS = this._fnGetMasterSettings(); 667 668 nButton.className = "DTTT_button "+o.sButtonClass; 669 nButton.setAttribute('id', "ToolTables_"+this.s.dt.sInstance+"_"+masterS.buttonCounter ); 670 nButton.appendChild( nSpan ); 671 nSpan.innerHTML = o.sButtonText; 672 673 masterS.buttonCounter++; 674 675 return nButton; 676 }, 677 678 679 /** 680 * Get the settings object for the master instance. When more than one TableTools instance is 681 * assigned to a DataTable, only one of them can be the 'master' (for the select rows). As such, 682 * we will typically want to interact with that master for global properties. 683 * @method _fnGetMasterSettings 684 * @returns {Object} TableTools settings object 685 * @private 686 */ 687 _fnGetMasterSettings: function () 688 { 689 if ( this.s.master ) 690 { 691 return this.s; 692 } 693 else 694 { 695 /* Look for the master which has the same DT as this one */ 696 var instances = TableTools._aInstances; 697 for ( var i=0, iLen=instances.length ; i<iLen ; i++ ) 698 { 699 if ( this.dom.table == instances[i].s.dt.nTable ) 700 { 701 return instances[i].s; 702 } 703 } 704 } 705 }, 706 707 708 709 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 710 * Button collection functions 711 */ 712 713 /** 714 * Create a collection button, when activated will present a drop downlist of other buttons 715 * @param {Node} nButton Button to use for the collection activation 716 * @param {Object} oConfig Button configuration object 717 * @returns void 718 * @private 719 */ 720 _fnCollectionConfig: function ( nButton, oConfig ) 721 { 722 var nHidden = document.createElement('div'); 723 nHidden.style.display = "none"; 724 nHidden.className = !this.s.dt.bJUI ? "DTTT_collection" : 725 "DTTT_collection ui-buttonset ui-buttonset-multi"; 726 oConfig._collection = nHidden; 727 728 this._fnButtonDefinations( oConfig.aButtons, nHidden ); 729 }, 730 731 732 /** 733 * Show a button collection 734 * @param {Node} nButton Button to use for the collection 735 * @param {Object} oConfig Button configuration object 736 * @returns void 737 * @private 738 */ 739 _fnCollectionShow: function ( nButton, oConfig ) 740 { 741 var 742 that = this, 743 oPos = $(nButton).offset(), 744 nHidden = oConfig._collection, 745 iDivX = oPos.left, 746 iDivY = oPos.top + $(nButton).outerHeight(), 747 iWinHeight = $(window).height(), iDocHeight = $(document).height(), 748 iWinWidth = $(window).width(), iDocWidth = $(document).width(); 749 750 nHidden.style.position = "absolute"; 751 nHidden.style.left = iDivX+"px"; 752 nHidden.style.top = iDivY+"px"; 753 nHidden.style.display = "block"; 754 $(nHidden).css('opacity',0); 755 756 var nBackground = document.createElement('div'); 757 nBackground.style.position = "absolute"; 758 nBackground.style.left = "0px"; 759 nBackground.style.top = "0px"; 760 nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px"; 761 nBackground.style.width = ((iWinWidth>iDocWidth)? iWinWidth : iDocWidth) +"px"; 762 nBackground.className = "DTTT_collection_background"; 763 $(nBackground).css('opacity',0); 764 765 document.body.appendChild( nBackground ); 766 document.body.appendChild( nHidden ); 767 768 /* Visual corrections to try and keep the collection visible */ 769 var iDivWidth = $(nHidden).outerWidth(); 770 var iDivHeight = $(nHidden).outerHeight(); 771 772 if ( iDivX + iDivWidth > iDocWidth ) 773 { 774 nHidden.style.left = (iDocWidth-iDivWidth)+"px"; 775 } 776 777 if ( iDivY + iDivHeight > iDocHeight ) 778 { 779 nHidden.style.top = (iDivY-iDivHeight-$(nButton).outerHeight())+"px"; 780 } 781 782 this.dom.collection.collection = nHidden; 783 this.dom.collection.background = nBackground; 784 785 /* This results in a very small delay for the end user but it allows the animation to be 786 * much smoother. If you don't want the animation, then the setTimeout can be removed 787 */ 788 setTimeout( function () { 789 $(nHidden).animate({opacity: 1}, 500); 790 $(nBackground).animate({opacity: 0.25}, 500); 791 }, 10 ); 792 793 /* Event handler to remove the collection display */ 794 $(nBackground).click( function () { 795 that._fnCollectionHide.call( that, null, null ); 796 } ); 797 }, 798 799 800 /** 801 * Hide a button collection 802 * @param {Node} nButton Button to use for the collection 803 * @param {Object} oConfig Button configuration object 804 * @returns void 805 * @private 806 */ 807 _fnCollectionHide: function ( nButton, oConfig ) 808 { 809 if ( oConfig !== null && oConfig.sExtends == 'collection' ) 810 { 811 return; 812 } 813 814 if ( this.dom.collection.collection !== null ) 815 { 816 $(this.dom.collection.collection).animate({opacity: 0}, 500, function (e) { 817 this.style.display = "none"; 818 } ); 819 820 $(this.dom.collection.background).animate({opacity: 0}, 500, function (e) { 821 this.parentNode.removeChild( this ); 822 } ); 823 824 this.dom.collection.collection = null; 825 this.dom.collection.background = null; 826 } 827 }, 828 829 830 831 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 832 * Row selection functions 833 */ 834 835 /** 836 * Add event handlers to a table to allow for row selection 837 * @method _fnRowSelectConfig 838 * @returns void 839 * @private 840 */ 841 _fnRowSelectConfig: function () 842 { 843 if ( this.s.master ) 844 { 845 var 846 that = this, 847 i, iLen, 848 aoOpenRows = this.s.dt.aoOpenRows; 849 850 $(that.s.dt.nTable).addClass( 'DTTT_selectable' ); 851 852 $('tr', that.s.dt.nTBody).live( 'click', function(e) { 853 /* Sub-table must be ignored (odd that the selector won't do this with >) */ 854 if ( this.parentNode != that.s.dt.nTBody ) 855 { 856 return; 857 } 858 859 /* Not interested in selecting 'opened' rows */ 860 for ( i=0, iLen=aoOpenRows.length ; i<iLen ; i++ ) 861 { 862 if ( this == aoOpenRows[i].nTr ) 863 { 864 return; 865 } 866 } 867 868 /* User defined selection function */ 869 if ( that.s.select.preRowSelect !== null && !that.s.select.preRowSelect.call(that, e) ) 870 { 871 return; 872 } 873 874 /* And go */ 875 if ( that.s.select.type == "single" ) 876 { 877 that._fnRowSelectSingle.call( that, this ); 878 } 879 else 880 { 881 that._fnRowSelectMulti.call( that, this ); 882 } 883 } ); 884 885 /* Add a draw callback handler for when 'select' all is active and we are using server-side 886 * processing, so TableTools will automatically select the new rows for us 887 */ 888 that.s.dt.aoDrawCallback.push( { 889 fn: function () { 890 if ( that.s.select.all && that.s.dt.oFeatures.bServerSide ) 891 { 892 that.fnSelectAll(); 893 } 894 }, 895 sName: "TableTools_select" 896 } ); 897 } 898 }, 899 900 901 /** 902 * Select or deselect a row based on its current state when only one row is allowed to be 903 * selected at a time (i.e. if there is a row already selected, deselect it). If the selected 904 * row is the one being passed in, just deselect and take no further action. 905 * @method _fnRowSelectSingle 906 * @param {Node} nNode TR element which is being 'activated' in some way 907 * @returns void 908 * @private 909 */ 910 _fnRowSelectSingle: function ( nNode ) 911 { 912 if ( this.s.master ) 913 { 914 /* Do nothing on the DataTables 'empty' result set row */ 915 if ( $('td', nNode).hasClass(this.s.dt.oClasses.sRowEmpty) ) 916 { 917 return; 918 } 919 920 if ( $(nNode).hasClass(this.s.select.selectedClass) ) 921 { 922 this._fnRowDeselect( nNode ); 923 } 924 else 925 { 926 if ( this.s.select.selected.length !== 0 ) 927 { 928 this._fnRowDeselectAll(); 929 } 930 931 this.s.select.selected.push( nNode ); 932 $(nNode).addClass( this.s.select.selectedClass ); 933 934 if ( this.s.select.postSelected !== null ) 935 { 936 this.s.select.postSelected.call( this, nNode ); 937 } 938 } 939 940 TableTools._fnEventDispatch( this, 'select', nNode ); 941 } 942 }, 943 944 945 /** 946 * Select or deselect a row based on its current state when multiple rows are allowed to be 947 * selected. 948 * @method _fnRowSelectMulti 949 * @param {Node} nNode TR element which is being 'activated' in some way 950 * @returns void 951 * @private 952 */ 953 _fnRowSelectMulti: function ( nNode ) 954 { 955 if ( this.s.master ) 956 { 957 /* Do nothing on the DataTables 'empty' result set row */ 958 if ( $('td', nNode).hasClass(this.s.dt.oClasses.sRowEmpty) ) 959 { 960 return; 961 } 962 963 if ( $(nNode).hasClass(this.s.select.selectedClass) ) 964 { 965 this._fnRowDeselect( nNode ); 966 } 967 else 968 { 969 this.s.select.selected.push( nNode ); 970 $(nNode).addClass( this.s.select.selectedClass ); 971 972 if ( this.s.select.postSelected !== null ) 973 { 974 this.s.select.postSelected.call( this, nNode ); 975 } 976 } 977 978 TableTools._fnEventDispatch( this, 'select', nNode ); 979 } 980 }, 981 982 983 /** 984 * Select all TR elements in the table. Note that this function will still operate in 'single' 985 * select mode, which might not be what you desire (in which case, don't call this function!) 986 * @method _fnRowSelectAll 987 * @returns void 988 * @private 989 */ 990 _fnRowSelectAll: function ( ) 991 { 992 if ( this.s.master ) 993 { 994 var n; 995 for ( var i=0, iLen=this.s.dt.aiDisplayMaster.length ; i<iLen ; i++ ) 996 { 997 n = this.s.dt.aoData[ this.s.dt.aiDisplayMaster[i] ].nTr; 998 999 if ( !$(n).hasClass(this.s.select.selectedClass) ) 1000 { 1001 this.s.select.selected.push( n ); 1002 $(n).addClass( this.s.select.selectedClass ); 1003 } 1004 } 1005 1006 this.s.select.all = true; 1007 TableTools._fnEventDispatch( this, 'select', null ); 1008 } 1009 }, 1010 1011 1012 /** 1013 * Deselect all TR elements in the table. If nothing is currently selected, then no action is 1014 * taken. 1015 * @method _fnRowDeselectAll 1016 * @returns void 1017 * @private 1018 */ 1019 _fnRowDeselectAll: function ( ) 1020 { 1021 if ( this.s.master ) 1022 { 1023 for ( var i=this.s.select.selected.length-1 ; i>=0 ; i-- ) 1024 { 1025 this._fnRowDeselect( i ); 1026 } 1027 1028 this.s.select.all = false; 1029 TableTools._fnEventDispatch( this, 'select', null ); 1030 } 1031 }, 1032 1033 1034 /** 1035 * Deselect a single row, based on its index in the selected array, or a TR node (when the 1036 * index is then computed) 1037 * @method _fnRowDeselect 1038 * @param {int|Node} i Node or index of node in selected array, which is to be deselected 1039 * @returns void 1040 * @private 1041 */ 1042 _fnRowDeselect: function ( i ) 1043 { 1044 if ( typeof i.nodeName != 'undefined' ) 1045 { 1046 i = $.inArray( i, this.s.select.selected ); 1047 } 1048 1049 var nNode = this.s.select.selected[i]; 1050 $(nNode).removeClass(this.s.select.selectedClass); 1051 this.s.select.selected.splice( i, 1 ); 1052 1053 if ( this.s.select.postDeselected !== null ) 1054 { 1055 this.s.select.postDeselected.call( this, nNode ); 1056 } 1057 1058 this.s.select.all = false; 1059 }, 1060 1061 1062 1063 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1064 * Text button functions 1065 */ 1066 1067 /** 1068 * Configure a text based button for interaction events 1069 * @method _fnTextConfig 1070 * @param {Node} nButton Button element which is being considered 1071 * @param {Object} oConfig Button configuration object 1072 * @returns void 1073 * @private 1074 */ 1075 _fnTextConfig: function ( nButton, oConfig ) 1076 { 1077 var that = this; 1078 1079 if ( oConfig.fnInit !== null ) 1080 { 1081 oConfig.fnInit.call( this, nButton, oConfig ); 1082 } 1083 1084 if ( oConfig.sToolTip !== "" ) 1085 { 1086 nButton.title = oConfig.sToolTip; 1087 } 1088 1089 $(nButton).hover( function () { 1090 $(nButton).removeClass( oConfig.sButtonClass ). 1091 addClass(oConfig.sButtonClassHover ); 1092 if ( oConfig.fnMouseover !== null ) 1093 { 1094 oConfig.fnMouseover.call( this, nButton, oConfig, null ); 1095 } 1096 }, function () { 1097 $(nButton).removeClass( oConfig.sButtonClassHover ). 1098 addClass( oConfig.sButtonClass ); 1099 if ( oConfig.fnMouseout !== null ) 1100 { 1101 oConfig.fnMouseout.call( this, nButton, oConfig, null ); 1102 } 1103 } ); 1104 1105 if ( oConfig.fnSelect !== null ) 1106 { 1107 TableTools._fnEventListen( this, 'select', function (n) { 1108 oConfig.fnSelect.call( that, nButton, oConfig, n ); 1109 } ); 1110 } 1111 1112 $(nButton).click( function (e) { 1113 e.preventDefault(); 1114 1115 if ( oConfig.fnClick !== null ) 1116 { 1117 oConfig.fnClick.call( that, nButton, oConfig, null ); 1118 } 1119 1120 /* Provide a complete function to match the behaviour of the flash elements */ 1121 if ( oConfig.fnComplete !== null ) 1122 { 1123 oConfig.fnComplete.call( that, nButton, oConfig, null, null ); 1124 } 1125 1126 that._fnCollectionHide( nButton, oConfig ); 1127 } ); 1128 }, 1129 1130 1131 1132 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1133 * Flash button functions 1134 */ 1135 1136 /** 1137 * Configure a flash based button for interaction events 1138 * @method _fnFlashConfig 1139 * @param {Node} nButton Button element which is being considered 1140 * @param {o} oConfig Button configuration object 1141 * @returns void 1142 * @private 1143 */ 1144 _fnFlashConfig: function ( nButton, oConfig ) 1145 { 1146 var that = this; 1147 var flash = new ZeroClipboard.Client(); 1148 1149 if ( oConfig.fnInit !== null ) 1150 { 1151 oConfig.fnInit.call( this, nButton, oConfig ); 1152 } 1153 1154 flash.setHandCursor( true ); 1155 1156 if ( oConfig.sAction == "flash_save" ) 1157 { 1158 flash.setAction( 'save' ); 1159 flash.setCharSet( (oConfig.sCharSet=="utf16le") ? 'UTF16LE' : 'UTF8' ); 1160 flash.setBomInc( oConfig.bBomInc ); 1161 flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) ); 1162 } 1163 else if ( oConfig.sAction == "flash_pdf" ) 1164 { 1165 flash.setAction( 'pdf' ); 1166 flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) ); 1167 } 1168 else 1169 { 1170 flash.setAction( 'copy' ); 1171 } 1172 1173 flash.addEventListener('mouseOver', function(client) { 1174 $(nButton).removeClass( oConfig.sButtonClass ). 1175 addClass(oConfig.sButtonClassHover ); 1176 1177 if ( oConfig.fnMouseover !== null ) 1178 { 1179 oConfig.fnMouseover.call( that, nButton, oConfig, flash ); 1180 } 1181 } ); 1182 1183 flash.addEventListener('mouseOut', function(client) { 1184 $(nButton).removeClass( oConfig.sButtonClassHover ). 1185 addClass(oConfig.sButtonClass ); 1186 1187 if ( oConfig.fnMouseout !== null ) 1188 { 1189 oConfig.fnMouseout.call( that, nButton, oConfig, flash ); 1190 } 1191 } ); 1192 1193 flash.addEventListener('mouseDown', function(client) { 1194 if ( oConfig.fnClick !== null ) 1195 { 1196 oConfig.fnClick.call( that, nButton, oConfig, flash ); 1197 } 1198 } ); 1199 1200 flash.addEventListener('complete', function (client, text) { 1201 if ( oConfig.fnComplete !== null ) 1202 { 1203 oConfig.fnComplete.call( that, nButton, oConfig, flash, text ); 1204 } 1205 that._fnCollectionHide( nButton, oConfig ); 1206 } ); 1207 1208 this._fnFlashGlue( flash, nButton, oConfig.sToolTip ); 1209 }, 1210 1211 1212 /** 1213 * Wait until the id is in the DOM before we "glue" the swf. Note that this function will call 1214 * itself (using setTimeout) until it completes successfully 1215 * @method _fnFlashGlue 1216 * @param {Object} clip Zero clipboard object 1217 * @param {Node} node node to glue swf to 1218 * @param {String} text title of the flash movie 1219 * @returns void 1220 * @private 1221 */ 1222 _fnFlashGlue: function ( flash, node, text ) 1223 { 1224 var that = this; 1225 var id = node.getAttribute('id'); 1226 1227 if ( document.getElementById(id) ) 1228 { 1229 flash.glue( node, text ); 1230 1231 /* Catch those who are using a TableTools 1 version of ZeroClipboard */ 1232 if ( flash.domElement.parentNode != flash.div.parentNode && 1233 typeof that.__bZCWarning == 'undefined' ) 1234 { 1235 that.s.dt.oApi._fnLog( this.s.dt, 0, "It looks like you are using the version of "+ 1236 "ZeroClipboard which came with TableTools 1. Please update to use the version that "+ 1237 "came with TableTools 2." ); 1238 that.__bZCWarning = true; 1239 } 1240 } 1241 else 1242 { 1243 setTimeout( function () { 1244 that._fnFlashGlue( flash, node, text ); 1245 }, 100 ); 1246 } 1247 }, 1248 1249 1250 /** 1251 * Set the text for the flash clip to deal with 1252 * 1253 * This function is required for large information sets. There is a limit on the 1254 * amount of data that can be transfered between Javascript and Flash in a single call, so 1255 * we use this method to build up the text in Flash by sending over chunks. It is estimated 1256 * that the data limit is around 64k, although it is undocuments, and appears to be different 1257 * between different flash versions. We chunk at 8KiB. 1258 * @method _fnFlashSetText 1259 * @param {Object} clip the ZeroClipboard object 1260 * @param {String} sData the data to be set 1261 * @returns void 1262 * @private 1263 */ 1264 _fnFlashSetText: function ( clip, sData ) 1265 { 1266 var asData = this._fnChunkData( sData, 8192 ); 1267 1268 clip.clearText(); 1269 for ( var i=0, iLen=asData.length ; i<iLen ; i++ ) 1270 { 1271 clip.appendText( asData[i] ); 1272 } 1273 }, 1274 1275 1276 1277 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1278 * Data retrieval functions 1279 */ 1280 1281 /** 1282 * Convert the mixed columns variable into a boolean array the same size as the columns, which 1283 * indicates which columns we want to include 1284 * @method _fnColumnTargets 1285 * @param {String|Array} mColumns The columns to be included in data retreieval. If a string 1286 * then it can take the value of "visible" or "hidden" (to include all visible or 1287 * hidden columns respectively). Or an array of column indexes 1288 * @returns {Array} A boolean array the length of the columns of the table, which each value 1289 * indicating if the column is to be included or not 1290 * @private 1291 */ 1292 _fnColumnTargets: function ( mColumns ) 1293 { 1294 var aColumns = []; 1295 var dt = this.s.dt; 1296 1297 if ( typeof mColumns == "object" ) 1298 { 1299 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 1300 { 1301 aColumns.push( false ); 1302 } 1303 1304 for ( i=0, iLen=mColumns.length ; i<iLen ; i++ ) 1305 { 1306 aColumns[ mColumns[i] ] = true; 1307 } 1308 } 1309 else if ( mColumns == "visible" ) 1310 { 1311 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 1312 { 1313 aColumns.push( dt.aoColumns[i].bVisible ? true : false ); 1314 } 1315 } 1316 else if ( mColumns == "hidden" ) 1317 { 1318 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 1319 { 1320 aColumns.push( dt.aoColumns[i].bVisible ? false : true ); 1321 } 1322 } 1323 else /* all */ 1324 { 1325 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 1326 { 1327 aColumns.push( true ); 1328 } 1329 } 1330 1331 return aColumns; 1332 }, 1333 1334 1335 /** 1336 * New line character(s) depend on the platforms 1337 * @method method 1338 * @param {Object} oConfig Button configuration object - only interested in oConfig.sNewLine 1339 * @returns {String} Newline character 1340 */ 1341 _fnNewline: function ( oConfig ) 1342 { 1343 if ( oConfig.sNewLine == "auto" ) 1344 { 1345 return navigator.userAgent.match(/Windows/) ? "\r\n" : "\n"; 1346 } 1347 else 1348 { 1349 return oConfig.sNewLine; 1350 } 1351 }, 1352 1353 1354 /** 1355 * Get data from DataTables' internals and format it for output 1356 * @method _fnGetDataTablesData 1357 * @param {Object} oConfig Button configuration object 1358 * @param {String} oConfig.sFieldBoundary Field boundary for the data cells in the string 1359 * @param {String} oConfig.sFieldSeperator Field seperator for the data cells 1360 * @param {String} oConfig.sNewline New line options 1361 * @param {Mixed} oConfig.mColumns Which columns should be included in the output 1362 * @param {Boolean} oConfig.bHeader Include the header 1363 * @param {Boolean} oConfig.bFooter Include the footer 1364 * @param {Boolean} oConfig.bSelectedOnly Include only the selected rows in the output 1365 * @returns {String} Concatinated string of data 1366 * @private 1367 */ 1368 _fnGetDataTablesData: function ( oConfig ) 1369 { 1370 var i, iLen, j, jLen; 1371 var sData = '', sLoopData = ''; 1372 var dt = this.s.dt; 1373 var regex = new RegExp(oConfig.sFieldBoundary, "g"); /* Do it here for speed */ 1374 var aColumnsInc = this._fnColumnTargets( oConfig.mColumns ); 1375 var sNewline = this._fnNewline( oConfig ); 1376 1377 /* 1378 * Header 1379 */ 1380 if ( oConfig.bHeader ) 1381 { 1382 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 1383 { 1384 if ( aColumnsInc[i] ) 1385 { 1386 sLoopData = dt.aoColumns[i].sTitle.replace(/\n/g," ").replace( /<.*?>/g, "" ); 1387 sLoopData = this._fnHtmlDecode( sLoopData ); 1388 1389 sData += this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) + 1390 oConfig.sFieldSeperator; 1391 } 1392 } 1393 sData = sData.slice( 0, oConfig.sFieldSeperator.length*-1 ); 1394 sData += sNewline; 1395 } 1396 1397 /* 1398 * Body 1399 */ 1400 for ( j=0, jLen=dt.aiDisplay.length ; j<jLen ; j++ ) 1401 { 1402 if ( typeof oConfig.bSelectedOnly && oConfig.bSelectedOnly && 1403 !$(dt.aoData[ dt.aiDisplay[j] ].nTr).hasClass( this.s.select.selectedClass ) ) 1404 { 1405 continue; 1406 } 1407 1408 /* Columns */ 1409 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 1410 { 1411 if ( aColumnsInc[i] ) 1412 { 1413 /* Convert to strings (with small optimisation) */ 1414 var mTypeData = dt.aoData[ dt.aiDisplay[j] ]._aData[ i ]; 1415 if ( typeof mTypeData == "string" ) 1416 { 1417 /* Strip newlines, replace img tags with alt attr. and finally strip html... */ 1418 sLoopData = mTypeData.replace(/\n/g," "); 1419 sLoopData = 1420 sLoopData.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi, 1421 '$1$2$3'); 1422 sLoopData = sLoopData.replace( /<.*?>/g, "" ); 1423 } 1424 else 1425 { 1426 sLoopData = mTypeData+""; 1427 } 1428 1429 /* Trim and clean the data */ 1430 sLoopData = sLoopData.replace(/^\s+/, '').replace(/\s+$/, ''); 1431 sLoopData = this._fnHtmlDecode( sLoopData ); 1432 1433 /* Bound it and add it to the total data */ 1434 sData += this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) + 1435 oConfig.sFieldSeperator; 1436 } 1437 } 1438 sData = sData.slice( 0, oConfig.sFieldSeperator.length*-1 ); 1439 sData += sNewline; 1440 } 1441 1442 /* Remove the last new line */ 1443 sData.slice( 0, -1 ); 1444 1445 /* 1446 * Footer 1447 */ 1448 if ( oConfig.bFooter ) 1449 { 1450 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 1451 { 1452 if ( aColumnsInc[i] && dt.aoColumns[i].nTf !== null ) 1453 { 1454 sLoopData = dt.aoColumns[i].nTf.innerHTML.replace(/\n/g," ").replace( /<.*?>/g, "" ); 1455 sLoopData = this._fnHtmlDecode( sLoopData ); 1456 1457 sData += this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) + 1458 oConfig.sFieldSeperator; 1459 } 1460 } 1461 sData = sData.slice( 0, oConfig.sFieldSeperator.length*-1 ); 1462 } 1463 1464 /* No pointers here - this is a string copy :-) */ 1465 _sLastData = sData; 1466 return sData; 1467 }, 1468 1469 1470 /** 1471 * Wrap data up with a boundary string 1472 * @method _fnBoundData 1473 * @param {String} sData data to bound 1474 * @param {String} sBoundary bounding char(s) 1475 * @param {RegExp} regex search for the bounding chars - constructed outside for efficincy 1476 * in the loop 1477 * @returns {String} bound data 1478 * @private 1479 */ 1480 _fnBoundData: function ( sData, sBoundary, regex ) 1481 { 1482 if ( sBoundary === "" ) 1483 { 1484 return sData; 1485 } 1486 else 1487 { 1488 return sBoundary + sData.replace(regex, "\\"+sBoundary) + sBoundary; 1489 } 1490 }, 1491 1492 1493 /** 1494 * Break a string up into an array of smaller strings 1495 * @method _fnChunkData 1496 * @param {String} sData data to be broken up 1497 * @param {Int} iSize chunk size 1498 * @returns {Array} String array of broken up text 1499 * @private 1500 */ 1501 _fnChunkData: function ( sData, iSize ) 1502 { 1503 var asReturn = []; 1504 var iStrlen = sData.length; 1505 1506 for ( var i=0 ; i<iStrlen ; i+=iSize ) 1507 { 1508 if ( i+iSize < iStrlen ) 1509 { 1510 asReturn.push( sData.substring( i, i+iSize ) ); 1511 } 1512 else 1513 { 1514 asReturn.push( sData.substring( i, iStrlen ) ); 1515 } 1516 } 1517 1518 return asReturn; 1519 }, 1520 1521 1522 /** 1523 * Decode HTML entities 1524 * @method _fnHtmlDecode 1525 * @param {String} sData encoded string 1526 * @returns {String} decoded string 1527 * @private 1528 */ 1529 _fnHtmlDecode: function ( sData ) 1530 { 1531 if ( sData.indexOf('&') == -1 ) 1532 { 1533 return sData; 1534 } 1535 1536 var 1537 aData = this._fnChunkData( sData, 2048 ), 1538 n = document.createElement('div'), 1539 i, iLen, iIndex, 1540 sReturn = "", sInner; 1541 1542 /* nodeValue has a limit in browsers - so we chunk the data into smaller segments to build 1543 * up the string. Note that the 'trick' here is to remember than we might have split over 1544 * an HTML entity, so we backtrack a little to make sure this doesn't happen 1545 */ 1546 for ( i=0, iLen=aData.length ; i<iLen ; i++ ) 1547 { 1548 /* Magic number 8 is because no entity is longer then strlen 8 in ISO 8859-1 */ 1549 iIndex = aData[i].lastIndexOf( '&' ); 1550 if ( iIndex != -1 && aData[i].length >= 8 && iIndex > aData[i].length - 8 ) 1551 { 1552 sInner = aData[i].substr( iIndex ); 1553 aData[i] = aData[i].substr( 0, iIndex ); 1554 } 1555 1556 n.innerHTML = aData[i]; 1557 sReturn += n.childNodes[0].nodeValue; 1558 } 1559 1560 return sReturn; 1561 }, 1562 1563 1564 1565 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1566 * Printing functions 1567 */ 1568 1569 /** 1570 * Configure a button for printing 1571 * @method _fnPrintConfig 1572 * @param {Node} nButton Button element which is being considered 1573 * @param {Object} oConfig Button configuration object 1574 * @returns void 1575 * @private 1576 */ 1577 _fnPrintConfig: function ( nButton, oConfig ) 1578 { 1579 var that = this; 1580 1581 if ( oConfig.fnInit !== null ) 1582 { 1583 oConfig.fnInit.call( this, nButton, oConfig ); 1584 } 1585 1586 $(nButton).hover( function () { 1587 $(nButton).removeClass( oConfig.sButtonClass ). 1588 addClass(oConfig.sButtonClassHover ); 1589 }, function () { 1590 $(nButton).removeClass( oConfig.sButtonClassHover ). 1591 addClass(oConfig.sButtonClass ); 1592 } ); 1593 1594 if ( oConfig.fnSelect !== null ) 1595 { 1596 TableTools._fnEventListen( this, 'select', function (n) { 1597 oConfig.fnSelect.call( that, nButton, oConfig, n ); 1598 } ); 1599 } 1600 1601 $(nButton).click( function (e) { 1602 e.preventDefault(); 1603 1604 that._fnPrintStart.call( that, e, oConfig); 1605 1606 if ( oConfig.fnClick !== null ) 1607 { 1608 oConfig.fnClick.call( that, nButton, oConfig, null ); 1609 } 1610 1611 /* Provide a complete function to match the behaviour of the flash elements */ 1612 if ( oConfig.fnComplete !== null ) 1613 { 1614 oConfig.fnComplete.call( that, nButton, oConfig, null, null ); 1615 } 1616 1617 that._fnCollectionHide( nButton, oConfig ); 1618 } ); 1619 }, 1620 1621 /** 1622 * Show print display 1623 * @method _fnPrintStart 1624 * @param {Event} e Event object 1625 * @param {Object} oConfig Button configuration object 1626 * @returns void 1627 * @private 1628 */ 1629 _fnPrintStart: function ( e, oConfig ) 1630 { 1631 var that = this; 1632 var oSetDT = this.s.dt; 1633 1634 /* Parse through the DOM hiding everything that isn't needed for the table */ 1635 this._fnPrintHideNodes( oSetDT.nTable ); 1636 1637 /* Show the whole table */ 1638 this.s.print.saveStart = oSetDT._iDisplayStart; 1639 this.s.print.saveLength = oSetDT._iDisplayLength; 1640 1641 if ( oConfig.bShowAll ) 1642 { 1643 oSetDT._iDisplayStart = 0; 1644 oSetDT._iDisplayLength = -1; 1645 oSetDT.oApi._fnCalculateEnd( oSetDT ); 1646 oSetDT.oApi._fnDraw( oSetDT ); 1647 } 1648 1649 /* Adjust the display for scrolling which might be done by DataTables */ 1650 if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" ) 1651 { 1652 this._fnPrintScrollStart( oSetDT ); 1653 } 1654 1655 /* Remove the other DataTables feature nodes - but leave the table! and info div */ 1656 var anFeature = oSetDT.aanFeatures; 1657 for ( var cFeature in anFeature ) 1658 { 1659 if ( cFeature != 'i' && cFeature != 't' && cFeature.length == 1 ) 1660 { 1661 for ( var i=0, iLen=anFeature[cFeature].length ; i<iLen ; i++ ) 1662 { 1663 this.dom.print.hidden.push( { 1664 node: anFeature[cFeature][i], 1665 display: "block" 1666 } ); 1667 anFeature[cFeature][i].style.display = "none"; 1668 } 1669 } 1670 } 1671 1672 /* Print class can be used for styling */ 1673 $(document.body).addClass( 'DTTT_Print' ); 1674 1675 /* Add a node telling the user what is going on */ 1676 if ( oConfig.sInfo !== "" ) 1677 { 1678 var nInfo = document.createElement( "div" ); 1679 nInfo.className = "DTTT_print_info"; 1680 nInfo.innerHTML = oConfig.sInfo; 1681 document.body.appendChild( nInfo ); 1682 1683 setTimeout( function() { 1684 $(nInfo).fadeOut( "normal", function() { 1685 document.body.removeChild( nInfo ); 1686 } ); 1687 }, 2000 ); 1688 } 1689 1690 /* Add a message at the top of the page */ 1691 if ( oConfig.sMessage !== "" ) 1692 { 1693 this.dom.print.message = document.createElement( "div" ); 1694 this.dom.print.message.className = "DTTT_PrintMessage"; 1695 this.dom.print.message.innerHTML = oConfig.sMessage; 1696 document.body.insertBefore( this.dom.print.message, document.body.childNodes[0] ); 1697 } 1698 1699 /* Cache the scrolling and the jump to the top of the t=page */ 1700 this.s.print.saveScroll = $(window).scrollTop(); 1701 window.scrollTo( 0, 0 ); 1702 1703 this.s.print.funcEnd = function(e) { 1704 that._fnPrintEnd.call( that, e ); 1705 }; 1706 $(document).bind( "keydown", null, this.s.print.funcEnd ); 1707 }, 1708 1709 1710 /** 1711 * Printing is finished, resume normal display 1712 * @method _fnPrintEnd 1713 * @param {Event} e Event object 1714 * @returns void 1715 * @private 1716 */ 1717 _fnPrintEnd: function ( e ) 1718 { 1719 /* Only interested in the escape key */ 1720 if ( e.keyCode == 27 ) 1721 { 1722 e.preventDefault(); 1723 1724 var that = this; 1725 var oSetDT = this.s.dt; 1726 var oSetPrint = this.s.print; 1727 var oDomPrint = this.dom.print; 1728 1729 /* Show all hidden nodes */ 1730 this._fnPrintShowNodes(); 1731 1732 /* Restore DataTables' scrolling */ 1733 if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" ) 1734 { 1735 this._fnPrintScrollEnd(); 1736 } 1737 1738 /* Restore the scroll */ 1739 window.scrollTo( 0, oSetPrint.saveScroll ); 1740 1741 /* Drop the print message */ 1742 if ( oDomPrint.message !== null ) 1743 { 1744 document.body.removeChild( oDomPrint.message ); 1745 oDomPrint.message = null; 1746 } 1747 1748 /* Styling class */ 1749 $(document.body).removeClass( 'DTTT_Print' ); 1750 1751 /* Restore the table length */ 1752 oSetDT._iDisplayStart = oSetPrint.saveStart; 1753 oSetDT._iDisplayLength = oSetPrint.saveLength; 1754 oSetDT.oApi._fnCalculateEnd( oSetDT ); 1755 oSetDT.oApi._fnDraw( oSetDT ); 1756 1757 $(document).unbind( "keydown", this.s.print.funcEnd ); 1758 this.s.print.funcEnd = null; 1759 } 1760 }, 1761 1762 1763 /** 1764 * Take account of scrolling in DataTables by showing the full table 1765 * @returns void 1766 * @private 1767 */ 1768 _fnPrintScrollStart: function () 1769 { 1770 var 1771 oSetDT = this.s.dt, 1772 nScrollHeadInner = oSetDT.nScrollHead.getElementsByTagName('div')[0], 1773 nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], 1774 nScrollBody = oSetDT.nTable.parentNode; 1775 1776 /* Copy the header in the thead in the body table, this way we show one single table when 1777 * in print view. Note that this section of code is more or less verbatim from DT 1.7.0 1778 */ 1779 var nTheadSize = oSetDT.nTable.getElementsByTagName('thead'); 1780 if ( nTheadSize.length > 0 ) 1781 { 1782 oSetDT.nTable.removeChild( nTheadSize[0] ); 1783 } 1784 1785 if ( oSetDT.nTFoot !== null ) 1786 { 1787 var nTfootSize = oSetDT.nTable.getElementsByTagName('tfoot'); 1788 if ( nTfootSize.length > 0 ) 1789 { 1790 oSetDT.nTable.removeChild( nTfootSize[0] ); 1791 } 1792 } 1793 1794 nTheadSize = oSetDT.nTHead.cloneNode(true); 1795 oSetDT.nTable.insertBefore( nTheadSize, oSetDT.nTable.childNodes[0] ); 1796 1797 if ( oSetDT.nTFoot !== null ) 1798 { 1799 nTfootSize = oSetDT.nTFoot.cloneNode(true); 1800 oSetDT.nTable.insertBefore( nTfootSize, oSetDT.nTable.childNodes[1] ); 1801 } 1802 1803 /* Now adjust the table's viewport so we can actually see it */ 1804 if ( oSetDT.oScroll.sX !== "" ) 1805 { 1806 oSetDT.nTable.style.width = $(oSetDT.nTable).outerWidth()+"px"; 1807 nScrollBody.style.width = $(oSetDT.nTable).outerWidth()+"px"; 1808 nScrollBody.style.overflow = "visible"; 1809 } 1810 1811 if ( oSetDT.oScroll.sY !== "" ) 1812 { 1813 nScrollBody.style.height = $(oSetDT.nTable).outerHeight()+"px"; 1814 nScrollBody.style.overflow = "visible"; 1815 } 1816 }, 1817 1818 1819 /** 1820 * Take account of scrolling in DataTables by showing the full table. Note that the redraw of 1821 * the DataTable that we do will actually deal with the majority of the hardword here 1822 * @returns void 1823 * @private 1824 */ 1825 _fnPrintScrollEnd: function () 1826 { 1827 var 1828 oSetDT = this.s.dt, 1829 nScrollBody = oSetDT.nTable.parentNode; 1830 1831 if ( oSetDT.oScroll.sX !== "" ) 1832 { 1833 nScrollBody.style.width = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sX ); 1834 nScrollBody.style.overflow = "auto"; 1835 } 1836 1837 if ( oSetDT.oScroll.sY !== "" ) 1838 { 1839 nScrollBody.style.height = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sY ); 1840 nScrollBody.style.overflow = "auto"; 1841 } 1842 }, 1843 1844 1845 /** 1846 * Resume the display of all TableTools hidden nodes 1847 * @method _fnPrintShowNodes 1848 * @returns void 1849 * @private 1850 */ 1851 _fnPrintShowNodes: function ( ) 1852 { 1853 var anHidden = this.dom.print.hidden; 1854 1855 for ( var i=0, iLen=anHidden.length ; i<iLen ; i++ ) 1856 { 1857 anHidden[i].node.style.display = anHidden[i].display; 1858 } 1859 anHidden.splice( 0, anHidden.length ); 1860 }, 1861 1862 1863 /** 1864 * Hide nodes which are not needed in order to display the table. Note that this function is 1865 * recursive 1866 * @method _fnPrintHideNodes 1867 * @param {Node} nNode Element which should be showing in a 'print' display 1868 * @returns void 1869 * @private 1870 */ 1871 _fnPrintHideNodes: function ( nNode ) 1872 { 1873 var anHidden = this.dom.print.hidden; 1874 1875 var nParent = nNode.parentNode; 1876 var nChildren = nParent.childNodes; 1877 for ( var i=0, iLen=nChildren.length ; i<iLen ; i++ ) 1878 { 1879 if ( nChildren[i] != nNode && nChildren[i].nodeType == 1 ) 1880 { 1881 /* If our node is shown (don't want to show nodes which were previously hidden) */ 1882 var sDisplay = $(nChildren[i]).css("display"); 1883 if ( sDisplay != "none" ) 1884 { 1885 /* Cache the node and it's previous state so we can restore it */ 1886 anHidden.push( { 1887 node: nChildren[i], 1888 display: sDisplay 1889 } ); 1890 nChildren[i].style.display = "none"; 1891 } 1892 } 1893 } 1894 1895 if ( nParent.nodeName != "BODY" ) 1896 { 1897 this._fnPrintHideNodes( nParent ); 1898 } 1899 } 1900 }; 1901 1902 1903 1904 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1905 * Static variables 1906 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1907 1908 /** 1909 * Store of all instances that have been created of TableTools, so one can look up other (when 1910 * there is need of a master) 1911 * @property _aInstances 1912 * @type Array 1913 * @default [] 1914 * @private 1915 */ 1916 TableTools._aInstances = []; 1917 1918 1919 /** 1920 * Store of all listeners and their callback functions 1921 * @property _aListeners 1922 * @type Array 1923 * @default [] 1924 */ 1925 TableTools._aListeners = []; 1926 1927 1928 1929 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1930 * Static methods 1931 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1932 1933 /** 1934 * Get an array of all the master instances 1935 * @method fnGetMasters 1936 * @returns {Array} List of master TableTools instances 1937 * @static 1938 */ 1939 TableTools.fnGetMasters = function () 1940 { 1941 var a = []; 1942 for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ ) 1943 { 1944 if ( TableTools._aInstances[i].s.master ) 1945 { 1946 a.push( TableTools._aInstances[i].s ); 1947 } 1948 } 1949 return a; 1950 }; 1951 1952 /** 1953 * Get the master instance for a table node (or id if a string is given) 1954 * @method fnGetInstance 1955 * @returns {Object} ID of table OR table node, for which we want the TableTools instance 1956 * @static 1957 */ 1958 TableTools.fnGetInstance = function ( node ) 1959 { 1960 if ( typeof node != 'object' ) 1961 { 1962 node = document.getElementById(node); 1963 } 1964 1965 for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ ) 1966 { 1967 if ( TableTools._aInstances[i].s.master && TableTools._aInstances[i].dom.table == node ) 1968 { 1969 return TableTools._aInstances[i]; 1970 } 1971 } 1972 return null; 1973 }; 1974 1975 1976 /** 1977 * Add a listener for a specific event 1978 * @method _fnEventListen 1979 * @param {Object} that Scope of the listening function (i.e. 'this' in the caller) 1980 * @param {String} type Event type 1981 * @param {Function} fn Function 1982 * @returns void 1983 * @private 1984 * @static 1985 */ 1986 TableTools._fnEventListen = function ( that, type, fn ) 1987 { 1988 TableTools._aListeners.push( { 1989 that: that, 1990 type: type, 1991 fn: fn 1992 } ); 1993 }; 1994 1995 1996 /** 1997 * An event has occured - look up every listener and fire it off. We check that the event we are 1998 * going to fire is attached to the same table (using the table node as reference) before firing 1999 * @method _fnEventDispatch 2000 * @param {Object} that Scope of the listening function (i.e. 'this' in the caller) 2001 * @param {String} type Event type 2002 * @param {Node} node Element that the event occured on (may be null) 2003 * @returns void 2004 * @private 2005 * @static 2006 */ 2007 TableTools._fnEventDispatch = function ( that, type, node ) 2008 { 2009 var listeners = TableTools._aListeners; 2010 for ( var i=0, iLen=listeners.length ; i<iLen ; i++ ) 2011 { 2012 if ( that.dom.table == listeners[i].that.dom.table && listeners[i].type == type ) 2013 { 2014 listeners[i].fn( node ); 2015 } 2016 } 2017 }; 2018 2019 2020 2021 2022 2023 2024 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2025 * Constants 2026 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2027 2028 2029 /** 2030 * @namespace Default button configurations 2031 */ 2032 TableTools.BUTTONS = { 2033 csv: { 2034 sAction: "flash_save", 2035 sCharSet: "utf8", 2036 bBomInc: false, 2037 sFileName: "*.csv", 2038 sFieldBoundary: "'", 2039 sFieldSeperator: ",", 2040 sNewLine: "auto", 2041 sTitle: "", 2042 sToolTip: "", 2043 sButtonClass: "DTTT_button_csv", 2044 sButtonClassHover: "DTTT_button_csv_hover", 2045 sButtonText: "CSV", 2046 mColumns: "all", /* "all", "visible", "hidden" or array of column integers */ 2047 bHeader: true, 2048 bFooter: true, 2049 bSelectedOnly: false, 2050 fnMouseover: null, 2051 fnMouseout: null, 2052 fnClick: function( nButton, oConfig, flash ) { 2053 this.fnSetText( flash, this.fnGetTableData(oConfig) ); 2054 }, 2055 fnSelect: null, 2056 fnComplete: null, 2057 fnInit: null 2058 }, 2059 xls: { 2060 sAction: "flash_save", 2061 sCharSet: "utf16le", 2062 bBomInc: true, 2063 sFileName: "*.csv", 2064 sFieldBoundary: "", 2065 sFieldSeperator: "\t", 2066 sNewLine: "auto", 2067 sTitle: "", 2068 sToolTip: "", 2069 sButtonClass: "DTTT_button_xls", 2070 sButtonClassHover: "DTTT_button_xls_hover", 2071 sButtonText: "Excel", 2072 mColumns: "all", 2073 bHeader: true, 2074 bFooter: true, 2075 bSelectedOnly: false, 2076 fnMouseover: null, 2077 fnMouseout: null, 2078 fnClick: function( nButton, oConfig, flash ) { 2079 this.fnSetText( flash, this.fnGetTableData(oConfig) ); 2080 }, 2081 fnSelect: null, 2082 fnComplete: null, 2083 fnInit: null 2084 }, 2085 copy: { 2086 sAction: "flash_copy", 2087 sFieldBoundary: "", 2088 sFieldSeperator: "\t", 2089 sNewLine: "auto", 2090 sToolTip: "", 2091 sButtonClass: "DTTT_button_copy", 2092 sButtonClassHover: "DTTT_button_copy_hover", 2093 sButtonText: "Copy", 2094 mColumns: "all", 2095 bHeader: true, 2096 bFooter: true, 2097 bSelectedOnly: false, 2098 fnMouseover: null, 2099 fnMouseout: null, 2100 fnClick: function( nButton, oConfig, flash ) { 2101 this.fnSetText( flash, this.fnGetTableData(oConfig) ); 2102 }, 2103 fnSelect: null, 2104 fnComplete: function(nButton, oConfig, flash, text) { 2105 var 2106 lines = text.split('\n').length, 2107 len = this.s.dt.nTFoot === null ? lines-1 : lines-2, 2108 plural = (len==1) ? "" : "s"; 2109 alert( 'Copied '+len+' row'+plural+' to the clipboard' ); 2110 }, 2111 fnInit: null 2112 }, 2113 pdf: { 2114 sAction: "flash_pdf", 2115 sFieldBoundary: "", 2116 sFieldSeperator: "\t", 2117 sNewLine: "\n", 2118 sFileName: "*.pdf", 2119 sToolTip: "", 2120 sTitle: "", 2121 sButtonClass: "DTTT_button_pdf", 2122 sButtonClassHover: "DTTT_button_pdf_hover", 2123 sButtonText: "PDF", 2124 mColumns: "all", 2125 bHeader: true, 2126 bFooter: false, 2127 bSelectedOnly: false, 2128 fnMouseover: null, 2129 fnMouseout: null, 2130 sPdfOrientation: "portrait", 2131 sPdfSize: "A4", 2132 sPdfMessage: "", 2133 fnClick: function( nButton, oConfig, flash ) { 2134 this.fnSetText( flash, 2135 "title:"+ this.fnGetTitle(oConfig) +"\n"+ 2136 "message:"+ oConfig.sPdfMessage +"\n"+ 2137 "colWidth:"+ this.fnCalcColRatios(oConfig) +"\n"+ 2138 "orientation:"+ oConfig.sPdfOrientation +"\n"+ 2139 "size:"+ oConfig.sPdfSize +"\n"+ 2140 "--/TableToolsOpts--\n" + 2141 this.fnGetTableData(oConfig) 2142 ); 2143 }, 2144 fnSelect: null, 2145 fnComplete: null, 2146 fnInit: null 2147 }, 2148 print: { 2149 sAction: "print", 2150 sInfo: "<h6>Print view</h6><p>Please use your browser's print function to "+ 2151 "print this table. Press escape when finished.", 2152 sMessage: "", 2153 bShowAll: true, 2154 sToolTip: "View print view", 2155 sButtonClass: "DTTT_button_print", 2156 sButtonClassHover: "DTTT_button_print_hover", 2157 sButtonText: "Print", 2158 fnMouseover: null, 2159 fnMouseout: null, 2160 fnClick: null, 2161 fnSelect: null, 2162 fnComplete: null, 2163 fnInit: null 2164 }, 2165 text: { 2166 sAction: "text", 2167 sToolTip: "", 2168 sButtonClass: "DTTT_button_text", 2169 sButtonClassHover: "DTTT_button_text_hover", 2170 sButtonText: "Text button", 2171 mColumns: "all", 2172 bHeader: true, 2173 bFooter: true, 2174 bSelectedOnly: false, 2175 fnMouseover: null, 2176 fnMouseout: null, 2177 fnClick: null, 2178 fnSelect: null, 2179 fnComplete: null, 2180 fnInit: null 2181 }, 2182 select: { 2183 sAction: "text", 2184 sToolTip: "", 2185 sButtonClass: "DTTT_button_text", 2186 sButtonClassHover: "DTTT_button_text_hover", 2187 sButtonText: "Select button", 2188 mColumns: "all", 2189 bHeader: true, 2190 bFooter: true, 2191 fnMouseover: null, 2192 fnMouseout: null, 2193 fnClick: null, 2194 fnSelect: function( nButton, oConfig ) { 2195 if ( this.fnGetSelected().length !== 0 ) { 2196 $(nButton).removeClass('DTTT_disabled'); 2197 } else { 2198 $(nButton).addClass('DTTT_disabled'); 2199 } 2200 }, 2201 fnComplete: null, 2202 fnInit: function( nButton, oConfig ) { 2203 $(nButton).addClass('DTTT_disabled'); 2204 } 2205 }, 2206 select_single: { 2207 sAction: "text", 2208 sToolTip: "", 2209 sButtonClass: "DTTT_button_text", 2210 sButtonClassHover: "DTTT_button_text_hover", 2211 sButtonText: "Select button", 2212 mColumns: "all", 2213 bHeader: true, 2214 bFooter: true, 2215 fnMouseover: null, 2216 fnMouseout: null, 2217 fnClick: null, 2218 fnSelect: function( nButton, oConfig ) { 2219 var iSelected = this.fnGetSelected().length; 2220 if ( iSelected == 1 ) { 2221 $(nButton).removeClass('DTTT_disabled'); 2222 } else { 2223 $(nButton).addClass('DTTT_disabled'); 2224 } 2225 }, 2226 fnComplete: null, 2227 fnInit: function( nButton, oConfig ) { 2228 $(nButton).addClass('DTTT_disabled'); 2229 } 2230 }, 2231 select_all: { 2232 sAction: "text", 2233 sToolTip: "", 2234 sButtonClass: "DTTT_button_text", 2235 sButtonClassHover: "DTTT_button_text_hover", 2236 sButtonText: "Select all", 2237 mColumns: "all", 2238 bHeader: true, 2239 bFooter: true, 2240 fnMouseover: null, 2241 fnMouseout: null, 2242 fnClick: function( nButton, oConfig ) { 2243 this.fnSelectAll(); 2244 }, 2245 fnSelect: function( nButton, oConfig ) { 2246 if ( this.fnGetSelected().length == this.s.dt.fnRecordsDisplay() ) { 2247 $(nButton).addClass('DTTT_disabled'); 2248 } else { 2249 $(nButton).removeClass('DTTT_disabled'); 2250 } 2251 }, 2252 fnComplete: null, 2253 fnInit: null 2254 }, 2255 select_none: { 2256 sAction: "text", 2257 sToolTip: "", 2258 sButtonClass: "DTTT_button_text", 2259 sButtonClassHover: "DTTT_button_text_hover", 2260 sButtonText: "Deselect all", 2261 mColumns: "all", 2262 bHeader: true, 2263 bFooter: true, 2264 fnMouseover: null, 2265 fnMouseout: null, 2266 fnClick: function( nButton, oConfig ) { 2267 this.fnSelectNone(); 2268 }, 2269 fnSelect: function( nButton, oConfig ) { 2270 if ( this.fnGetSelected().length !== 0 ) { 2271 $(nButton).removeClass('DTTT_disabled'); 2272 } else { 2273 $(nButton).addClass('DTTT_disabled'); 2274 } 2275 }, 2276 fnComplete: null, 2277 fnInit: function( nButton, oConfig ) { 2278 $(nButton).addClass('DTTT_disabled'); 2279 } 2280 }, 2281 ajax: { 2282 sAction: "text", 2283 sFieldBoundary: "", 2284 sFieldSeperator: "\t", 2285 sNewLine: "\n", 2286 sAjaxUrl: "/xhr.php", 2287 sToolTip: "", 2288 sButtonClass: "DTTT_button_text", 2289 sButtonClassHover: "DTTT_button_text_hover", 2290 sButtonText: "Ajax button", 2291 mColumns: "all", 2292 bHeader: true, 2293 bFooter: true, 2294 bSelectedOnly: false, 2295 fnMouseover: null, 2296 fnMouseout: null, 2297 fnClick: function( nButton, oConfig ) { 2298 var sData = this.fnGetTableData(oConfig); 2299 $.ajax( { 2300 url: oConfig.sAjaxUrl, 2301 data: [ 2302 { name: "tableData", value: sData } 2303 ], 2304 success: oConfig.fnAjaxComplete, 2305 dataType: "json", 2306 type: "POST", 2307 cache: false, 2308 error: function () { 2309 alert( "Error detected when sending table data to server" ); 2310 } 2311 } ); 2312 }, 2313 fnSelect: null, 2314 fnComplete: null, 2315 fnInit: null, 2316 fnAjaxComplete: function( json ) { 2317 alert( 'Ajax complete' ); 2318 } 2319 }, 2320 collection: { 2321 sAction: "collection", 2322 sToolTip: "", 2323 sButtonClass: "DTTT_button_collection", 2324 sButtonClassHover: "DTTT_button_collection_hover", 2325 sButtonText: "Collection", 2326 fnMouseover: null, 2327 fnMouseout: null, 2328 fnClick: function( nButton, oConfig ) { 2329 this._fnCollectionShow(nButton, oConfig); 2330 }, 2331 fnSelect: null, 2332 fnComplete: null, 2333 fnInit: null 2334 } 2335 }; 2336 /* 2337 * on* callback parameters: 2338 * 1. node - button element 2339 * 2. object - configuration object for this button 2340 * 3. object - ZeroClipboard reference (flash button only) 2341 * 4. string - Returned string from Flash (flash button only - and only on 'complete') 2342 */ 2343 2344 2345 /** 2346 * @namespace TableTools default settings for initialisation 2347 */ 2348 TableTools.DEFAULTS = { 2349 sSwfPath: "media/swf/copy_cvs_xls_pdf.swf", 2350 sRowSelect: "none", 2351 sSelectedClass: "DTTT_selected", 2352 fnPreRowSelect: null, 2353 fnRowSelected: null, 2354 fnRowDeselected: null, 2355 aButtons: [ "copy", "csv", "xls", "pdf", "print" ] 2356 }; 2357 2358 2359 /** 2360 * Name of this class 2361 * @constant CLASS 2362 * @type String 2363 * @default TableTools 2364 */ 2365 TableTools.prototype.CLASS = "TableTools"; 2366 2367 2368 /** 2369 * TableTools version 2370 * @constant VERSION 2371 * @type String 2372 * @default 2.0.1 2373 */ 2374 TableTools.VERSION = "2.0.1"; 2375 TableTools.prototype.VERSION = TableTools.VERSION; 2376 2377 2378 2379 2380 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2381 * Initialisation 2382 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2383 2384 /* 2385 * Register a new feature with DataTables 2386 */ 2387 if ( typeof $.fn.dataTable == "function" && 2388 typeof $.fn.dataTableExt.fnVersionCheck == "function" && 2389 $.fn.dataTableExt.fnVersionCheck('1.7.0') ) 2390 { 2391 $.fn.dataTableExt.aoFeatures.push( { 2392 fnInit: function( oDTSettings ) { 2393 var oOpts = typeof oDTSettings.oInit.oTableTools != 'undefined' ? 2394 oDTSettings.oInit.oTableTools : {}; 2395 2396 var oTT = new TableTools( oDTSettings.oInstance, oOpts ); 2397 TableTools._aInstances.push( oTT ); 2398 2399 return oTT.dom.container; 2400 }, 2401 cFeature: "T", 2402 sFeature: "TableTools" 2403 } ); 2404 } 2405 else 2406 { 2407 alert( "Warning: TableTools 2 requires DataTables 1.7 or greater - www.datatables.net/download"); 2408 } 2409 2410 })(jQuery, window, document); 2411