1/*! TableTools 2.2.4 2 * 2009-2015 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.4 12 * @file dataTables.tableTools.js 13 * @author SpryMedia Ltd (www.sprymedia.co.uk) 14 * @contact www.sprymedia.co.uk/contact 15 * @copyright Copyright 2009-2015 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-2015 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 742 TableTools._aInstances.push( this ); 743 this._fnConstruct( oOpts ); 744 745 return this; 746}; 747 748 749 750TableTools.prototype = { 751 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 752 * Public methods 753 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 754 755 /** 756 * Retreieve the settings object from an instance 757 * @returns {array} List of TR nodes which are currently selected 758 * @param {boolean} [filtered=false] Get only selected rows which are 759 * available given the filtering applied to the table. By default 760 * this is false - i.e. all rows, regardless of filtering are 761 selected. 762 */ 763 "fnGetSelected": function ( filtered ) 764 { 765 var 766 out = [], 767 data = this.s.dt.aoData, 768 displayed = this.s.dt.aiDisplay, 769 i, iLen; 770 771 if ( filtered ) 772 { 773 // Only consider filtered rows 774 for ( i=0, iLen=displayed.length ; i<iLen ; i++ ) 775 { 776 if ( data[ displayed[i] ]._DTTT_selected ) 777 { 778 out.push( data[ displayed[i] ].nTr ); 779 } 780 } 781 } 782 else 783 { 784 // Use all rows 785 for ( i=0, iLen=data.length ; i<iLen ; i++ ) 786 { 787 if ( data[i]._DTTT_selected ) 788 { 789 out.push( data[i].nTr ); 790 } 791 } 792 } 793 794 return out; 795 }, 796 797 798 /** 799 * Get the data source objects/arrays from DataTables for the selected rows (same as 800 * fnGetSelected followed by fnGetData on each row from the table) 801 * @returns {array} Data from the TR nodes which are currently selected 802 */ 803 "fnGetSelectedData": function () 804 { 805 var out = []; 806 var data=this.s.dt.aoData; 807 var i, iLen; 808 809 for ( i=0, iLen=data.length ; i<iLen ; i++ ) 810 { 811 if ( data[i]._DTTT_selected ) 812 { 813 out.push( this.s.dt.oInstance.fnGetData(i) ); 814 } 815 } 816 817 return out; 818 }, 819 820 821 /** 822 * Get the indexes of the selected rows 823 * @returns {array} List of row indexes 824 * @param {boolean} [filtered=false] Get only selected rows which are 825 * available given the filtering applied to the table. By default 826 * this is false - i.e. all rows, regardless of filtering are 827 selected. 828 */ 829 "fnGetSelectedIndexes": function ( filtered ) 830 { 831 var 832 out = [], 833 data = this.s.dt.aoData, 834 displayed = this.s.dt.aiDisplay, 835 i, iLen; 836 837 if ( filtered ) 838 { 839 // Only consider filtered rows 840 for ( i=0, iLen=displayed.length ; i<iLen ; i++ ) 841 { 842 if ( data[ displayed[i] ]._DTTT_selected ) 843 { 844 out.push( displayed[i] ); 845 } 846 } 847 } 848 else 849 { 850 // Use all rows 851 for ( i=0, iLen=data.length ; i<iLen ; i++ ) 852 { 853 if ( data[i]._DTTT_selected ) 854 { 855 out.push( i ); 856 } 857 } 858 } 859 860 return out; 861 }, 862 863 864 /** 865 * Check to see if a current row is selected or not 866 * @param {Node} n TR node to check if it is currently selected or not 867 * @returns {Boolean} true if select, false otherwise 868 */ 869 "fnIsSelected": function ( n ) 870 { 871 var pos = this.s.dt.oInstance.fnGetPosition( n ); 872 return (this.s.dt.aoData[pos]._DTTT_selected===true) ? true : false;
873 }, 874 875 876 /** 877 * Select all rows in the table 878 * @param {boolean} [filtered=false] Select only rows which are available 879 * given the filtering applied to the table. By default this is false - 880 * i.e. all rows, regardless of filtering are selected. 881 */ 882 "fnSelectAll": function ( filtered ) 883 { 884 this._fnRowSelect( filtered ? 885 this.s.dt.aiDisplay : 886 this.s.dt.aoData 887 ); 888 }, 889 890 891 /** 892 * Deselect all rows in the table 893 * @param {boolean} [filtered=false] Deselect only rows which are available 894 * given the filtering applied to the table. By default this is false - 895 * i.e. all rows, regardless of filtering are deselected. 896 */ 897 "fnSelectNone": function ( filtered ) 898 { 899 this._fnRowDeselect( this.fnGetSelectedIndexes(filtered) ); 900 }, 901 902 903 /** 904 * Select row(s) 905 * @param {node|object|array} n The row(s) to select. Can be a single DOM 906 * TR node, an array of TR nodes or a jQuery object. 907 */ 908 "fnSelect": function ( n ) 909 { 910 if ( this.s.select.type == "single" ) 911 { 912 this.fnSelectNone(); 913 this._fnRowSelect( n ); 914 } 915 else 916 { 917 this._fnRowSelect( n ); 918 } 919 }, 920 921 922 /** 923 * Deselect row(s) 924 * @param {node|object|array} n The row(s) to deselect. Can be a single DOM 925 * TR node, an array of TR nodes or a jQuery object. 926 */ 927 "fnDeselect": function ( n ) 928 { 929 this._fnRowDeselect( n ); 930 }, 931 932 933 /** 934 * Get the title of the document - useful for file names. The title is retrieved from either 935 * the configuration object's 'title' parameter, or the HTML document title 936 * @param {Object} oConfig Button configuration object 937 * @returns {String} Button title 938 */ 939 "fnGetTitle": function( oConfig ) 940 { 941 var sTitle = ""; 942 if ( typeof oConfig.sTitle != 'undefined' && oConfig.sTitle !== "" ) { 943 sTitle = oConfig.sTitle; 944 } else { 945 var anTitle = document.getElementsByTagName('title'); 946 if ( anTitle.length > 0 ) 947 { 948 sTitle = anTitle[0].innerHTML; 949 } 950 } 951 952 /* Strip characters which the OS will object to - checking for UTF8 support in the scripting 953 * engine 954 */ 955 if ( "\u00A1".toString().length < 4 ) { 956 return sTitle.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, ""); 957 } else { 958 return sTitle.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g, ""); 959 } 960 }, 961 962 963 /** 964 * Calculate a unity array with the column width by proportion for a set of columns to be 965 * included for a button. This is particularly useful for PDF creation, where we can use the 966 * column widths calculated by the browser to size the columns in the PDF. 967 * @param {Object} oConfig Button configuration object 968 * @returns {Array} Unity array of column ratios 969 */ 970 "fnCalcColRatios": function ( oConfig ) 971 { 972 var 973 aoCols = this.s.dt.aoColumns, 974 aColumnsInc = this._fnColumnTargets( oConfig.mColumns ), 975 aColWidths = [], 976 iWidth = 0, iTotal = 0, i, iLen; 977 978 for ( i=0, iLen=aColumnsInc.length ; i<iLen ; i++ ) 979 { 980 if ( aColumnsInc[i] ) 981 { 982 iWidth = aoCols[i].nTh.offsetWidth; 983 iTotal += iWidth; 984 aColWidths.push( iWidth ); 985 } 986 } 987 988 for ( i=0, iLen=aColWidths.length ; i<iLen ; i++ ) 989 { 990 aColWidths[i] = aColWidths[i] / iTotal; 991 } 992 993 return aColWidths.join('\t'); 994 }, 995 996 997 /** 998 * Get the information contained in a table as a string 999 * @param {Object} oConfig Button configuration object 1000 * @returns {String} Table data as a string 1001 */ 1002 "fnGetTableData": function ( oConfig ) 1003 { 1004 /* In future this could be used to get data from a plain HTML source as well as DataTables */ 1005 if ( this.s.dt ) 1006 { 1007 return this._fnGetDataTablesData( oConfig ); 1008 } 1009 }, 1010 1011 1012 /** 1013 * Pass text to a flash button instance, which will be used on the button's click handler 1014 * @param {Object} clip Flash button object 1015 * @param {String} text Text to set 1016 */ 1017 "fnSetText": function ( clip, text ) 1018 { 1019 this._fnFlashSetText( clip, text ); 1020 }, 1021 1022 1023 /** 1024 * Resize the flash elements of the buttons attached to this TableTools instance - this is 1025 * useful for when initialising TableTools when it is hidden (display:none) since sizes can't 1026 * be calculated at that time. 1027 */ 1028 "fnResizeButtons": function () 1029 { 1030 for ( var cli in ZeroClipboard_TableTools.clients ) 1031 { 1032 if ( cli ) 1033 { 1034 var client = ZeroClipboard_TableTools.clients[cli]; 1035 if ( typeof client.domElement != 'undefined' && 1036 client.domElement.parentNode ) 1037 { 1038 client.positionElement(); 1039 } 1040 } 1041 } 1042 }, 1043 1044 1045 /** 1046 * Check to see if any of the ZeroClipboard client's attached need to be resized 1047 */ 1048 "fnResizeRequired": function () 1049 { 1050 for ( var cli in ZeroClipboard_TableTools.clients ) 1051 { 1052 if ( cli ) 1053 { 1054 var client = ZeroClipboard_TableTools.clients[cli]; 1055 if ( typeof client.domElement != 'undefined' && 1056 client.domElement.parentNode == this.dom.container && 1057 client.sized === false ) 1058 { 1059 return true; 1060 } 1061 } 1062 } 1063 return false;
1064 }, 1065 1066 1067 /** 1068 * Programmatically enable or disable the print view 1069 * @param {boolean} [bView=true] Show the print view if true or not given. If false, then 1070 * terminate the print view and return to normal. 1071 * @param {object} [oConfig={}] Configuration for the print view 1072 * @param {boolean} [oConfig.bShowAll=false] Show all rows in the table if true 1073 * @param {string} [oConfig.sInfo] Information message, displayed as an overlay to the 1074 * user to let them know what the print view is. 1075 * @param {string} [oConfig.sMessage] HTML string to show at the top of the document - will 1076 * be included in the printed document. 1077 */ 1078 "fnPrint": function ( bView, oConfig ) 1079 { 1080 if ( oConfig === undefined ) 1081 { 1082 oConfig = {}; 1083 } 1084 1085 if ( bView === undefined || bView ) 1086 { 1087 this._fnPrintStart( oConfig ); 1088 } 1089 else 1090 { 1091 this._fnPrintEnd(); 1092 } 1093 }, 1094 1095 1096 /** 1097 * Show a message to the end user which is nicely styled 1098 * @param {string} message The HTML string to show to the user 1099 * @param {int} time The duration the message is to be shown on screen for (mS) 1100 */ 1101 "fnInfo": function ( message, time ) { 1102 var info = $('<div/>') 1103 .addClass( this.classes.print.info ) 1104 .html( message ) 1105 .appendTo( 'body' ); 1106 1107 setTimeout( function() { 1108 info.fadeOut( "normal", function() { 1109 info.remove(); 1110 } ); 1111 }, time ); 1112 }, 1113 1114 1115 1116 /** 1117 * Get the container element of the instance for attaching to the DOM 1118 * @returns {node} DOM node 1119 */ 1120 "fnContainer": function () { 1121 return this.dom.container; 1122 }, 1123 1124 1125 1126 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1127 * Private methods (they are of course public in JS, but recommended as private) 1128 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 1129 1130 /** 1131 * Constructor logic 1132 * @method _fnConstruct 1133 * @param {Object} oOpts Same as TableTools constructor 1134 * @returns void 1135 * @private 1136 */ 1137 "_fnConstruct": function ( oOpts ) 1138 { 1139 var that = this; 1140 1141 this._fnCustomiseSettings( oOpts ); 1142 1143 /* Container element */ 1144 this.dom.container = document.createElement( this.s.tags.container ); 1145 this.dom.container.className = this.classes.container; 1146 1147 /* Row selection config */ 1148 if ( this.s.select.type != 'none' ) 1149 { 1150 this._fnRowSelectConfig(); 1151 } 1152 1153 /* Buttons */ 1154 this._fnButtonDefinations( this.s.buttonSet, this.dom.container ); 1155 1156 /* Destructor */ 1157 this.s.dt.aoDestroyCallback.push( { 1158 "sName": "TableTools", 1159 "fn": function () { 1160 $(that.s.dt.nTBody) 1161 .off( 'click.DTTT_Select', that.s.custom.sRowSelector ) 1162 .off( 'mousedown.DTTT_Select', 'tr' ) 1163 .off( 'mouseup.DTTT_Select', 'tr' ); 1164 1165 $(that.dom.container).empty(); 1166 1167 // Remove the instance 1168 var idx = $.inArray( that, TableTools._aInstances ); 1169 if ( idx !== -1 ) { 1170 TableTools._aInstances.splice( idx, 1 ); 1171 } 1172 } 1173 } ); 1174 }, 1175 1176 1177 /** 1178 * Take the user defined settings and the default settings and combine them. 1179 * @method _fnCustomiseSettings 1180 * @param {Object} oOpts Same as TableTools constructor 1181 * @returns void 1182 * @private 1183 */ 1184 "_fnCustomiseSettings": function ( oOpts ) 1185 { 1186 /* Is this the master control instance or not? */ 1187 if ( typeof this.s.dt._TableToolsInit == 'undefined' ) 1188 { 1189 this.s.master = true; 1190 this.s.dt._TableToolsInit = true; 1191 } 1192 1193 /* We can use the table node from comparisons to group controls */ 1194 this.dom.table = this.s.dt.nTable; 1195 1196 /* Clone the defaults and then the user options */ 1197 this.s.custom = $.extend( {}, TableTools.DEFAULTS, oOpts ); 1198 1199 /* Flash file location */ 1200 this.s.swfPath = this.s.custom.sSwfPath; 1201 if ( typeof ZeroClipboard_TableTools != 'undefined' ) 1202 { 1203 ZeroClipboard_TableTools.moviePath = this.s.swfPath; 1204 } 1205 1206 /* Table row selecting */ 1207 this.s.select.type = this.s.custom.sRowSelect; 1208 this.s.select.preRowSelect = this.s.custom.fnPreRowSelect; 1209 this.s.select.postSelected = this.s.custom.fnRowSelected; 1210 this.s.select.postDeselected = this.s.custom.fnRowDeselected; 1211 1212 // Backwards compatibility - allow the user to specify a custom class in the initialiser 1213 if ( this.s.custom.sSelectedClass ) 1214 { 1215 this.classes.select.row = this.s.custom.sSelectedClass; 1216 } 1217 1218 this.s.tags = this.s.custom.oTags; 1219 1220 /* Button set */ 1221 this.s.buttonSet = this.s.custom.aButtons; 1222 }, 1223 1224 1225 /** 1226 * Take the user input arrays and expand them to be fully defined, and then add them to a given 1227 * DOM element 1228 * @method _fnButtonDefinations 1229 * @param {array} buttonSet Set of user defined buttons 1230 * @param {node} wrapper Node to add the created buttons to 1231 * @returns void 1232 * @private 1233 */ 1234 "_fnButtonDefinations": function ( buttonSet, wrapper ) 1235 { 1236 var buttonDef; 1237 1238 for ( var i=0, iLen=buttonSet.length ; i<iLen ; i++ ) 1239 { 1240 if ( typeof buttonSet[i] == "string" ) 1241 { 1242 if ( typeof TableTools.BUTTONS[ buttonSet[i] ] == 'undefined' ) 1243 { 1244 alert( "TableTools: Warning - unknown button type: "+buttonSet[i] ); 1245 continue; 1246 } 1247 buttonDef = $.extend( {}, TableTools.BUTTONS[ buttonSet[i] ], true ); 1248 } 1249 else 1250 {
1251 if ( typeof TableTools.BUTTONS[ buttonSet[i].sExtends ] == 'undefined' ) 1252 { 1253 alert( "TableTools: Warning - unknown button type: "+buttonSet[i].sExtends ); 1254 continue; 1255 } 1256 var o = $.extend( {}, TableTools.BUTTONS[ buttonSet[i].sExtends ], true ); 1257 buttonDef = $.extend( o, buttonSet[i], true ); 1258 } 1259 1260 var button = this._fnCreateButton( 1261 buttonDef, 1262 $(wrapper).hasClass(this.classes.collection.container) 1263 ); 1264 1265 if ( button ) { 1266 wrapper.appendChild( button ); 1267 } 1268 } 1269 }, 1270 1271 1272 /** 1273 * Create and configure a TableTools button 1274 * @method _fnCreateButton 1275 * @param {Object} oConfig Button configuration object 1276 * @returns {Node} Button element 1277 * @private 1278 */ 1279 "_fnCreateButton": function ( oConfig, bCollectionButton ) 1280 { 1281 var nButton = this._fnButtonBase( oConfig, bCollectionButton ); 1282 1283 if ( oConfig.sAction.match(/flash/) ) 1284 { 1285 if ( ! this._fnHasFlash() ) { 1286 return false; 1287 } 1288 1289 this._fnFlashConfig( nButton, oConfig ); 1290 } 1291 else if ( oConfig.sAction == "text" ) 1292 { 1293 this._fnTextConfig( nButton, oConfig ); 1294 } 1295 else if ( oConfig.sAction == "div" ) 1296 { 1297 this._fnTextConfig( nButton, oConfig ); 1298 } 1299 else if ( oConfig.sAction == "collection" ) 1300 { 1301 this._fnTextConfig( nButton, oConfig ); 1302 this._fnCollectionConfig( nButton, oConfig ); 1303 } 1304 1305 if ( this.s.dt.iTabIndex !== -1 ) { 1306 $(nButton) 1307 .attr( 'tabindex', this.s.dt.iTabIndex ) 1308 .attr( 'aria-controls', this.s.dt.sTableId ) 1309 .on( 'keyup.DTTT', function (e) { 1310 // Trigger the click event on return key when focused. 1311 // Note that for Flash buttons this has no effect since we 1312 // can't programmatically trigger the Flash export 1313 if ( e.keyCode === 13 ) { 1314 e.stopPropagation(); 1315 1316 $(this).trigger( 'click' ); 1317 } 1318 } ) 1319 .on( 'mousedown.DTTT', function (e) { 1320 // On mousedown we want to stop the focus occurring on the 1321 // button, focus is used only for the keyboard navigation. 1322 // But using preventDefault for the flash buttons stops the 1323 // flash action. However, it is not the button that gets 1324 // focused but the flash element for flash buttons, so this 1325 // works 1326 if ( ! oConfig.sAction.match(/flash/) ) { 1327 e.preventDefault(); 1328 } 1329 } ); 1330 } 1331 1332 return nButton; 1333 }, 1334 1335 1336 /** 1337 * Create the DOM needed for the button and apply some base properties. All buttons start here 1338 * @method _fnButtonBase 1339 * @param {o} oConfig Button configuration object 1340 * @returns {Node} DIV element for the button 1341 * @private 1342 */ 1343 "_fnButtonBase": function ( o, bCollectionButton ) 1344 { 1345 var sTag, sLiner, sClass; 1346 1347 if ( bCollectionButton ) 1348 { 1349 sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.collection.button; 1350 sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.collection.liner; 1351 sClass = this.classes.collection.buttons.normal; 1352 } 1353 else 1354 { 1355 sTag = o.sTag && o.sTag !== "default" ? o.sTag : this.s.tags.button; 1356 sLiner = o.sLinerTag && o.sLinerTag !== "default" ? o.sLiner : this.s.tags.liner; 1357 sClass = this.classes.buttons.normal; 1358 } 1359 1360 var 1361 nButton = document.createElement( sTag ), 1362 nSpan = document.createElement( sLiner ), 1363 masterS = this._fnGetMasterSettings(); 1364 1365 nButton.className = sClass+" "+o.sButtonClass; 1366 nButton.setAttribute('id', "ToolTables_"+this.s.dt.sInstance+"_"+masterS.buttonCounter ); 1367 nButton.appendChild( nSpan ); 1368 nSpan.innerHTML = o.sButtonText; 1369 1370 masterS.buttonCounter++; 1371 1372 return nButton; 1373 }, 1374 1375 1376 /** 1377 * Get the settings object for the master instance. When more than one TableTools instance is 1378 * assigned to a DataTable, only one of them can be the 'master' (for the select rows). As such, 1379 * we will typically want to interact with that master for global properties. 1380 * @method _fnGetMasterSettings 1381 * @returns {Object} TableTools settings object 1382 * @private 1383 */ 1384 "_fnGetMasterSettings": function () 1385 { 1386 if ( this.s.master ) 1387 { 1388 return this.s; 1389 } 1390 else 1391 { 1392 /* Look for the master which has the same DT as this one */ 1393 var instances = TableTools._aInstances; 1394 for ( var i=0, iLen=instances.length ; i<iLen ; i++ ) 1395 { 1396 if ( this.dom.table == instances[i].s.dt.nTable ) 1397 { 1398 return instances[i].s; 1399 } 1400 } 1401 } 1402 }, 1403 1404 1405 1406 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1407 * Button collection functions 1408 */ 1409 1410 /**
1411 * Create a collection button, when activated will present a drop down list of other buttons 1412 * @param {Node} nButton Button to use for the collection activation 1413 * @param {Object} oConfig Button configuration object 1414 * @returns void 1415 * @private 1416 */ 1417 "_fnCollectionConfig": function ( nButton, oConfig ) 1418 { 1419 var nHidden = document.createElement( this.s.tags.collection.container ); 1420 nHidden.style.display = "none"; 1421 nHidden.className = this.classes.collection.container; 1422 oConfig._collection = nHidden; 1423 document.body.appendChild( nHidden ); 1424 1425 this._fnButtonDefinations( oConfig.aButtons, nHidden ); 1426 }, 1427 1428 1429 /** 1430 * Show a button collection 1431 * @param {Node} nButton Button to use for the collection 1432 * @param {Object} oConfig Button configuration object 1433 * @returns void 1434 * @private 1435 */ 1436 "_fnCollectionShow": function ( nButton, oConfig ) 1437 { 1438 var 1439 that = this, 1440 oPos = $(nButton).offset(), 1441 nHidden = oConfig._collection, 1442 iDivX = oPos.left, 1443 iDivY = oPos.top + $(nButton).outerHeight(), 1444 iWinHeight = $(window).height(), iDocHeight = $(document).height(), 1445 iWinWidth = $(window).width(), iDocWidth = $(document).width(); 1446 1447 nHidden.style.position = "absolute"; 1448 nHidden.style.left = iDivX+"px"; 1449 nHidden.style.top = iDivY+"px"; 1450 nHidden.style.display = "block"; 1451 $(nHidden).css('opacity',0); 1452 1453 var nBackground = document.createElement('div'); 1454 nBackground.style.position = "absolute"; 1455 nBackground.style.left = "0px"; 1456 nBackground.style.top = "0px"; 1457 nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px"; 1458 nBackground.style.width = ((iWinWidth>iDocWidth)? iWinWidth : iDocWidth) +"px"; 1459 nBackground.className = this.classes.collection.background; 1460 $(nBackground).css('opacity',0); 1461 1462 document.body.appendChild( nBackground ); 1463 document.body.appendChild( nHidden ); 1464 1465 /* Visual corrections to try and keep the collection visible */ 1466 var iDivWidth = $(nHidden).outerWidth(); 1467 var iDivHeight = $(nHidden).outerHeight(); 1468 1469 if ( iDivX + iDivWidth > iDocWidth ) 1470 { 1471 nHidden.style.left = (iDocWidth-iDivWidth)+"px"; 1472 } 1473 1474 if ( iDivY + iDivHeight > iDocHeight ) 1475 { 1476 nHidden.style.top = (iDivY-iDivHeight-$(nButton).outerHeight())+"px"; 1477 } 1478 1479 this.dom.collection.collection = nHidden; 1480 this.dom.collection.background = nBackground; 1481 1482 /* This results in a very small delay for the end user but it allows the animation to be 1483 * much smoother. If you don't want the animation, then the setTimeout can be removed 1484 */ 1485 setTimeout( function () { 1486 $(nHidden).animate({"opacity": 1}, 500); 1487 $(nBackground).animate({"opacity": 0.25}, 500); 1488 }, 10 ); 1489 1490 /* Resize the buttons to the Flash contents fit */ 1491 this.fnResizeButtons(); 1492 1493 /* Event handler to remove the collection display */ 1494 $(nBackground).click( function () { 1495 that._fnCollectionHide.call( that, null, null ); 1496 } ); 1497 }, 1498 1499 1500 /** 1501 * Hide a button collection 1502 * @param {Node} nButton Button to use for the collection 1503 * @param {Object} oConfig Button configuration object 1504 * @returns void 1505 * @private 1506 */ 1507 "_fnCollectionHide": function ( nButton, oConfig ) 1508 { 1509 if ( oConfig !== null && oConfig.sExtends == 'collection' ) 1510 { 1511 return; 1512 } 1513 1514 if ( this.dom.collection.collection !== null ) 1515 { 1516 $(this.dom.collection.collection).animate({"opacity": 0}, 500, function (e) { 1517 this.style.display = "none"; 1518 } ); 1519 1520 $(this.dom.collection.background).animate({"opacity": 0}, 500, function (e) { 1521 this.parentNode.removeChild( this ); 1522 } ); 1523 1524 this.dom.collection.collection = null; 1525 this.dom.collection.background = null; 1526 } 1527 }, 1528 1529 1530 1531 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1532 * Row selection functions 1533 */ 1534 1535 /** 1536 * Add event handlers to a table to allow for row selection 1537 * @method _fnRowSelectConfig 1538 * @returns void 1539 * @private 1540 */ 1541 "_fnRowSelectConfig": function () 1542 { 1543 if ( this.s.master ) 1544 { 1545 var 1546 that = this, 1547 i, iLen, 1548 dt = this.s.dt, 1549 aoOpenRows = this.s.dt.aoOpenRows; 1550 1551 $(dt.nTable).addClass( this.classes.select.table ); 1552 1553 // When using OS style selection, we want to cancel the shift text 1554 // selection, but only when the shift key is used (so you can 1555 // actually still select text in the table) 1556 if ( this.s.select.type === 'os' ) { 1557 $(dt.nTBody).on( 'mousedown.DTTT_Select', 'tr', function(e) { 1558 if ( e.shiftKey ) { 1559 1560 $(dt.nTBody) 1561 .css( '-moz-user-select', 'none' ) 1562 .one('selectstart.DTTT_Select', 'tr', function () { 1563 return false;
1564 } ); 1565 } 1566 } ); 1567 1568 $(dt.nTBody).on( 'mouseup.DTTT_Select', 'tr', function(e) { 1569 $(dt.nTBody).css( '-moz-user-select', '' ); 1570 } ); 1571 } 1572 1573 // Row selection 1574 $(dt.nTBody).on( 'click.DTTT_Select', this.s.custom.sRowSelector, function(e) { 1575 var row = this.nodeName.toLowerCase() === 'tr' ? 1576 this : 1577 $(this).parents('tr')[0]; 1578 1579 var select = that.s.select; 1580 var pos = that.s.dt.oInstance.fnGetPosition( row ); 1581 1582 /* Sub-table must be ignored (odd that the selector won't do this with >) */ 1583 if ( row.parentNode != dt.nTBody ) { 1584 return; 1585 } 1586 1587 /* Check that we are actually working with a DataTables controlled row */ 1588 if ( dt.oInstance.fnGetData(row) === null ) { 1589 return; 1590 } 1591 1592 // Shift click, ctrl click and simple click handling to make 1593 // row selection a lot like a file system in desktop OSs 1594 if ( select.type == 'os' ) { 1595 if ( e.ctrlKey || e.metaKey ) { 1596 // Add or remove from the selection 1597 if ( that.fnIsSelected( row ) ) { 1598 that._fnRowDeselect( row, e ); 1599 } 1600 else { 1601 that._fnRowSelect( row, e ); 1602 } 1603 } 1604 else if ( e.shiftKey ) { 1605 // Add a range of rows, from the last selected row to 1606 // this one 1607 var rowIdxs = that.s.dt.aiDisplay.slice(); // visible rows 1608 var idx1 = $.inArray( select.lastRow, rowIdxs ); 1609 var idx2 = $.inArray( pos, rowIdxs ); 1610 1611 if ( that.fnGetSelected().length === 0 || idx1 === -1 ) { 1612 // select from top to here - slightly odd, but both 1613 // Windows and Mac OS do this 1614 rowIdxs.splice( $.inArray( pos, rowIdxs )+1, rowIdxs.length ); 1615 } 1616 else { 1617 // reverse so we can shift click 'up' as well as down 1618 if ( idx1 > idx2 ) { 1619 var tmp = idx2; 1620 idx2 = idx1; 1621 idx1 = tmp; 1622 } 1623 1624 rowIdxs.splice( idx2+1, rowIdxs.length ); 1625 rowIdxs.splice( 0, idx1 ); 1626 } 1627 1628 if ( ! that.fnIsSelected( row ) ) { 1629 // Select range 1630 that._fnRowSelect( rowIdxs, e ); 1631 } 1632 else { 1633 // Deselect range - need to keep the clicked on row selected 1634 rowIdxs.splice( $.inArray( pos, rowIdxs ), 1 ); 1635 that._fnRowDeselect( rowIdxs, e ); 1636 } 1637 } 1638 else { 1639 // No cmd or shift click. Deselect current if selected, 1640 // or select this row only 1641 if ( that.fnIsSelected( row ) && that.fnGetSelected().length === 1 ) { 1642 that._fnRowDeselect( row, e ); 1643 } 1644 else { 1645 that.fnSelectNone(); 1646 that._fnRowSelect( row, e ); 1647 } 1648 } 1649 } 1650 else if ( that.fnIsSelected( row ) ) { 1651 that._fnRowDeselect( row, e ); 1652 } 1653 else if ( select.type == "single" ) { 1654 that.fnSelectNone(); 1655 that._fnRowSelect( row, e ); 1656 } 1657 else if ( select.type == "multi" ) { 1658 that._fnRowSelect( row, e ); 1659 } 1660 1661 select.lastRow = pos; 1662 } );//.on('selectstart', function () { return false; } ); 1663 1664 // Bind a listener to the DataTable for when new rows are created. 1665 // This allows rows to be visually selected when they should be and 1666 // deferred rendering is used. 1667 dt.oApi._fnCallbackReg( dt, 'aoRowCreatedCallback', function (tr, data, index) { 1668 if ( dt.aoData[index]._DTTT_selected ) { 1669 $(tr).addClass( that.classes.select.row ); 1670 } 1671 }, 'TableTools-SelectAll' ); 1672 } 1673 }, 1674 1675 /** 1676 * Select rows 1677 * @param {*} src Rows to select - see _fnSelectData for a description of valid inputs 1678 * @private 1679 */ 1680 "_fnRowSelect": function ( src, e ) 1681 { 1682 var 1683 that = this, 1684 data = this._fnSelectData( src ), 1685 firstTr = data.length===0 ? null : data[0].nTr, 1686 anSelected = [], 1687 i, len; 1688 1689 // Get all the rows that will be selected 1690 for ( i=0, len=data.length ; i<len ; i++ ) 1691 { 1692 if ( data[i].nTr ) 1693 { 1694 anSelected.push( data[i].nTr ); 1695 } 1696 } 1697 1698 // User defined pre-selection function 1699 if ( this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anSelected, true) ) 1700 { 1701 return; 1702 } 1703 1704 // Mark them as selected 1705 for ( i=0, len=data.length ; i<len ; i++ ) 1706 { 1707 data[i]._DTTT_selected = true; 1708 1709 if ( data[i].nTr ) 1710 { 1711 $(data[i].nTr).addClass( that.classes.select.row ); 1712 } 1713 } 1714 1715 // Post-selection function 1716 if ( this.s.select.postSelected !== null ) 1717 { 1718 this.s.select.postSelected.call( this, anSelected ); 1719 } 1720 1721 TableTools._fnEventDispatch( this, 'select', anSelected, true ); 1722 }, 1723 1724 /** 1725 * Deselect rows 1726 * @param {*} src Rows to deselect - see _fnSelectData for a description of valid input
1726s 1727 * @private 1728 */ 1729 "_fnRowDeselect": function ( src, e ) 1730 { 1731 var 1732 that = this, 1733 data = this._fnSelectData( src ), 1734 firstTr = data.length===0 ? null : data[0].nTr, 1735 anDeselectedTrs = [], 1736 i, len; 1737 1738 // Get all the rows that will be deselected 1739 for ( i=0, len=data.length ; i<len ; i++ ) 1740 { 1741 if ( data[i].nTr ) 1742 { 1743 anDeselectedTrs.push( data[i].nTr ); 1744 } 1745 } 1746 1747 // User defined pre-selection function 1748 if ( this.s.select.preRowSelect !== null && !this.s.select.preRowSelect.call(this, e, anDeselectedTrs, false) ) 1749 { 1750 return; 1751 } 1752 1753 // Mark them as deselected 1754 for ( i=0, len=data.length ; i<len ; i++ ) 1755 { 1756 data[i]._DTTT_selected = false; 1757 1758 if ( data[i].nTr ) 1759 { 1760 $(data[i].nTr).removeClass( that.classes.select.row ); 1761 } 1762 } 1763 1764 // Post-deselection function 1765 if ( this.s.select.postDeselected !== null ) 1766 { 1767 this.s.select.postDeselected.call( this, anDeselectedTrs ); 1768 } 1769 1770 TableTools._fnEventDispatch( this, 'select', anDeselectedTrs, false ); 1771 }, 1772 1773 /** 1774 * Take a data source for row selection and convert it into aoData points for the DT 1775 * @param {*} src Can be a single DOM TR node, an array of TR nodes (including a 1776 * a jQuery object), a single aoData point from DataTables, an array of aoData 1777 * points or an array of aoData indexes 1778 * @returns {array} An array of aoData points 1779 */ 1780 "_fnSelectData": function ( src ) 1781 { 1782 var out = [], pos, i, iLen; 1783 1784 if ( src.nodeName ) 1785 { 1786 // Single node 1787 pos = this.s.dt.oInstance.fnGetPosition( src ); 1788 out.push( this.s.dt.aoData[pos] ); 1789 } 1790 else if ( typeof src.length !== 'undefined' ) 1791 { 1792 // jQuery object or an array of nodes, or aoData points 1793 for ( i=0, iLen=src.length ; i<iLen ; i++ ) 1794 { 1795 if ( src[i].nodeName ) 1796 { 1797 pos = this.s.dt.oInstance.fnGetPosition( src[i] ); 1798 out.push( this.s.dt.aoData[pos] ); 1799 } 1800 else if ( typeof src[i] === 'number' ) 1801 { 1802 out.push( this.s.dt.aoData[ src[i] ] ); 1803 } 1804 else 1805 { 1806 out.push( src[i] ); 1807 } 1808 } 1809 1810 return out; 1811 } 1812 else if ( typeof src === 'number' ) 1813 { 1814 out.push(this.s.dt.aoData[src]); 1815 } 1816 else 1817 { 1818 // A single aoData point 1819 out.push( src ); 1820 } 1821 1822 return out; 1823 }, 1824 1825 1826 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1827 * Text button functions 1828 */ 1829 1830 /** 1831 * Configure a text based button for interaction events 1832 * @method _fnTextConfig 1833 * @param {Node} nButton Button element which is being considered 1834 * @param {Object} oConfig Button configuration object 1835 * @returns void 1836 * @private 1837 */ 1838 "_fnTextConfig": function ( nButton, oConfig ) 1839 { 1840 var that = this; 1841 1842 if ( oConfig.fnInit !== null ) 1843 { 1844 oConfig.fnInit.call( this, nButton, oConfig ); 1845 } 1846 1847 if ( oConfig.sToolTip !== "" ) 1848 { 1849 nButton.title = oConfig.sToolTip; 1850 } 1851 1852 $(nButton).hover( function () { 1853 if ( oConfig.fnMouseover !== null ) 1854 { 1855 oConfig.fnMouseover.call( this, nButton, oConfig, null ); 1856 } 1857 }, function () { 1858 if ( oConfig.fnMouseout !== null ) 1859 { 1860 oConfig.fnMouseout.call( this, nButton, oConfig, null ); 1861 } 1862 } ); 1863 1864 if ( oConfig.fnSelect !== null ) 1865 { 1866 TableTools._fnEventListen( this, 'select', function (n) { 1867 oConfig.fnSelect.call( that, nButton, oConfig, n ); 1868 } ); 1869 } 1870 1871 $(nButton).click( function (e) { 1872 //e.preventDefault(); 1873 1874 if ( oConfig.fnClick !== null ) 1875 { 1876 oConfig.fnClick.call( that, nButton, oConfig, null, e ); 1877 } 1878 1879 /* Provide a complete function to match the behaviour of the flash elements */ 1880 if ( oConfig.fnComplete !== null ) 1881 { 1882 oConfig.fnComplete.call( that, nButton, oConfig, null, null ); 1883 } 1884 1885 that._fnCollectionHide( nButton, oConfig ); 1886 } ); 1887 }, 1888 1889 1890 1891 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1892 * Flash button functions 1893 */ 1894 1895 /** 1896 * Check if the Flash plug-in is available 1897 * @method _fnHasFlash 1898 * @returns {boolean} `true` if Flash available, `false` otherwise 1899 * @private 1900 */ 1901 "_fnHasFlash": function () 1902 { 1903 try { 1904 var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash'); 1905 if (fo) { 1906 return true; 1907 } 1908 } 1909 catch (e) { 1910 if ( 1911 navigator.mimeTypes && 1912 navigator.mimeTypes['application/x-shockwave-flash'] !== undefined && 1913 navigator.mimeTypes['application/x-shockwave-flash'].enabledPlugin 1914 ) { 1915 return true; 1916 } 1917 } 1918 1919 return false;
1920 }, 1921 1922 1923 /** 1924 * Configure a flash based button for interaction events 1925 * @method _fnFlashConfig 1926 * @param {Node} nButton Button element which is being considered 1927 * @param {o} oConfig Button configuration object 1928 * @returns void 1929 * @private 1930 */ 1931 "_fnFlashConfig": function ( nButton, oConfig ) 1932 { 1933 var that = this; 1934 var flash = new ZeroClipboard_TableTools.Client(); 1935 1936 if ( oConfig.fnInit !== null ) 1937 { 1938 oConfig.fnInit.call( this, nButton, oConfig ); 1939 } 1940 1941 flash.setHandCursor( true ); 1942 1943 if ( oConfig.sAction == "flash_save" ) 1944 { 1945 flash.setAction( 'save' ); 1946 flash.setCharSet( (oConfig.sCharSet=="utf16le") ? 'UTF16LE' : 'UTF8' ); 1947 flash.setBomInc( oConfig.bBomInc ); 1948 flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) ); 1949 } 1950 else if ( oConfig.sAction == "flash_pdf" ) 1951 { 1952 flash.setAction( 'pdf' ); 1953 flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) ); 1954 } 1955 else 1956 { 1957 flash.setAction( 'copy' ); 1958 } 1959 1960 flash.addEventListener('mouseOver', function(client) { 1961 if ( oConfig.fnMouseover !== null ) 1962 { 1963 oConfig.fnMouseover.call( that, nButton, oConfig, flash ); 1964 } 1965 } ); 1966 1967 flash.addEventListener('mouseOut', function(client) { 1968 if ( oConfig.fnMouseout !== null ) 1969 { 1970 oConfig.fnMouseout.call( that, nButton, oConfig, flash ); 1971 } 1972 } ); 1973 1974 flash.addEventListener('mouseDown', function(client) { 1975 if ( oConfig.fnClick !== null ) 1976 { 1977 oConfig.fnClick.call( that, nButton, oConfig, flash ); 1978 } 1979 } ); 1980 1981 flash.addEventListener('complete', function (client, text) { 1982 if ( oConfig.fnComplete !== null ) 1983 { 1984 oConfig.fnComplete.call( that, nButton, oConfig, flash, text ); 1985 } 1986 that._fnCollectionHide( nButton, oConfig ); 1987 } ); 1988 1989 if ( oConfig.fnSelect !== null ) 1990 { 1991 TableTools._fnEventListen( this, 'select', function (n) { 1992 oConfig.fnSelect.call( that, nButton, oConfig, n ); 1993 } ); 1994 } 1995 1996 this._fnFlashGlue( flash, nButton, oConfig.sToolTip ); 1997 }, 1998 1999 2000 /** 2001 * Wait until the id is in the DOM before we "glue" the swf. Note that this function will call 2002 * itself (using setTimeout) until it completes successfully 2003 * @method _fnFlashGlue 2004 * @param {Object} clip Zero clipboard object 2005 * @param {Node} node node to glue swf to 2006 * @param {String} text title of the flash movie 2007 * @returns void 2008 * @private 2009 */ 2010 "_fnFlashGlue": function ( flash, node, text ) 2011 { 2012 var that = this; 2013 var id = node.getAttribute('id'); 2014 2015 if ( document.getElementById(id) ) 2016 { 2017 flash.glue( node, text ); 2018 } 2019 else 2020 { 2021 setTimeout( function () { 2022 that._fnFlashGlue( flash, node, text ); 2023 }, 100 ); 2024 } 2025 }, 2026 2027 2028 /** 2029 * Set the text for the flash clip to deal with 2030 * 2031 * This function is required for large information sets. There is a limit on the 2032 * amount of data that can be transferred between Javascript and Flash in a single call, so 2033 * we use this method to build up the text in Flash by sending over chunks. It is estimated 2034 * that the data limit is around 64k, although it is undocumented, and appears to be different 2035 * between different flash versions. We chunk at 8KiB. 2036 * @method _fnFlashSetText 2037 * @param {Object} clip the ZeroClipboard object 2038 * @param {String} sData the data to be set 2039 * @returns void 2040 * @private 2041 */ 2042 "_fnFlashSetText": function ( clip, sData ) 2043 { 2044 var asData = this._fnChunkData( sData, 8192 ); 2045 2046 clip.clearText(); 2047 for ( var i=0, iLen=asData.length ; i<iLen ; i++ ) 2048 { 2049 clip.appendText( asData[i] ); 2050 } 2051 }, 2052 2053 2054 2055 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2056 * Data retrieval functions 2057 */ 2058 2059 /** 2060 * Convert the mixed columns variable into a boolean array the same size as the columns, which 2061 * indicates which columns we want to include 2062 * @method _fnColumnTargets 2063 * @param {String|Array} mColumns The columns to be included in data retrieval. If a string 2064 * then it can take the value of "visible" or "hidden" (to include all visible or 2065 * hidden columns respectively). Or an array of column indexes 2066 * @returns {Array} A boolean array the length of the columns of the table, which each value 2067 * indicating if the column is to be included or not 2068 * @private 2069 */ 2070 "_fnColumnTargets": function ( mColumns ) 2071 { 2072 var aColumns = []; 2073 var dt = this.s.dt; 2074 var i, iLen; 2075 var columns = dt.aoColumns; 2076 var columnCount = columns.length; 2077 2078 if ( typeof mColumns == "function" ) 2079 { 2080 var a = mColumns.call( this, dt ); 2081 2082 for ( i=0, iLen=columnCount ; i<iLen ; i++ ) 2083 { 2084 aColumns.push( $.inArray( i, a ) !== -1 ? true : false ); 2085 } 2086 } 2087 else if ( typeof mColumns == "object" ) 2088 { 2089 for ( i=0, iLen=columnCount ; i<iLen ; i++ ) 2090 { 2091 aColumns.push( false ); 2092 } 2093 2094 for ( i=0, iLen=mColumns.length ; i<iLen ; i++ ) 2095 { 2096 aColumns[ mColumns[i] ] = true; 2097 } 2098 } 2099 else if ( mColumns == "visible" ) 2100 { 2101 for ( i=0, iLen=columnCount ; i<iLen ; i++ ) 2102 { 2103 aColumns.push( columns[i].bVisible ? true : false ); 2104 } 2105 } 2106 else if ( mColumns == "hidden" ) 2107 { 2108 for ( i=0, iLen=columnCount ; i<iLen ; i++ ) 2109 { 2110 aColumns.push( columns[i].bVisible ? false : true ); 2111 } 2112 } 2113 else if ( mColumns == "sortable" ) 2114 { 2115 for ( i=0, iLen=columnCount ; i<iLen ; i++ ) 2116 { 2117 aColumns.push( columns[i].bSortable ? true : false ); 2118 } 2119 } 2120 else /* all */ 2121 { 2122 for ( i=0, iLen=columnCount ; i<iLen ; i++ ) 2123 { 2124 aColumns.push( true ); 2125 } 2126 } 2127 2128 return aColumns; 2129 }, 2130 2131 2132 /** 2133 * New line character(s) depend on the platforms 2134 * @method method 2135 * @param {Object} oConfig Button configuration object - only interested in oConfig.sNewLine 2136 * @returns {String} Newline character 2137 */ 2138 "_fnNewline": function ( oConfig ) 2139 { 2140 if ( oConfig.sNewLine == "auto" ) 2141 { 2142 return navigator.userAgent.match(/Windows/) ? "\r\n" : "\n"; 2143 } 2144 else 2145 { 2146 return oConfig.sNewLine; 2147 } 2148 }, 2149 2150 2151 /** 2152 * Get data from DataTables' internals and format it for output 2153 * @method _fnGetDataTablesData 2154 * @param {Object} oConfig Button configuration object
2155 * @param {String} oConfig.sFieldBoundary Field boundary for the data cells in the string 2156 * @param {String} oConfig.sFieldSeperator Field separator for the data cells 2157 * @param {String} oConfig.sNewline New line options 2158 * @param {Mixed} oConfig.mColumns Which columns should be included in the output 2159 * @param {Boolean} oConfig.bHeader Include the header 2160 * @param {Boolean} oConfig.bFooter Include the footer 2161 * @param {Boolean} oConfig.bSelectedOnly Include only the selected rows in the output 2162 * @returns {String} Concatenated string of data 2163 * @private 2164 */ 2165 "_fnGetDataTablesData": function ( oConfig ) 2166 { 2167 var i, iLen, j, jLen; 2168 var aRow, aData=[], sLoopData='', arr; 2169 var dt = this.s.dt, tr, child; 2170 var regex = new RegExp(oConfig.sFieldBoundary, "g"); /* Do it here for speed */ 2171 var aColumnsInc = this._fnColumnTargets( oConfig.mColumns ); 2172 var bSelectedOnly = (typeof oConfig.bSelectedOnly != 'undefined') ? oConfig.bSelectedOnly : false; 2173 2174 /* 2175 * Header 2176 */ 2177 if ( oConfig.bHeader ) 2178 { 2179 aRow = []; 2180 2181 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 2182 { 2183 if ( aColumnsInc[i] ) 2184 { 2185 sLoopData = dt.aoColumns[i].sTitle.replace(/\n/g," ").replace( /<.*?>/g, "" ).replace(/^\s+|\s+$/g,""); 2186 sLoopData = this._fnHtmlDecode( sLoopData ); 2187 2188 aRow.push( this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) ); 2189 } 2190 } 2191 2192 aData.push( aRow.join(oConfig.sFieldSeperator) ); 2193 } 2194 2195 bSelectedOnly = true; 2196 2197 /* 2198 * Body 2199 */ 2200 var aDataIndex; 2201 var aSelected = this.fnGetSelectedIndexes(); 2202 bSelectedOnly = this.s.select.type !== "none" && bSelectedOnly && aSelected.length !== 0; 2203 2204 if ( bSelectedOnly ) { 2205 // Use the selected indexes 2206 aDataIndex = aSelected; 2207 } 2208 else if ( DataTable.Api ) { 2209 // 1.10+ style 2210 aDataIndex = new DataTable.Api( dt ) 2211 .rows( oConfig.oSelectorOpts ) 2212 .indexes() 2213 .flatten() 2214 .toArray(); 2215 } 2216 else { 2217 // 1.9- style 2218 aDataIndex = dt.oInstance 2219 .$('tr', oConfig.oSelectorOpts) 2220 .map( function (id, row) { 2221 return dt.oInstance.fnGetPosition( row ); 2222 } ) 2223 .get(); 2224 } 2225 2226 for ( j=0, jLen=aDataIndex.length ; j<jLen ; j++ ) 2227 { 2228 tr = dt.aoData[ aDataIndex[j] ].nTr; 2229 aRow = []; 2230 2231 /* Columns */ 2232 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 2233 { 2234 if ( aColumnsInc[i] ) 2235 { 2236 /* Convert to strings (with small optimisation) */ 2237 var mTypeData = dt.oApi._fnGetCellData( dt, aDataIndex[j], i, 'display' ); 2238 if ( oConfig.fnCellRender ) 2239 { 2240 sLoopData = oConfig.fnCellRender( mTypeData, i, tr, aDataIndex[j] )+""; 2241 } 2242 else if ( typeof mTypeData == "string" ) 2243 { 2244 /* Strip newlines, replace img tags with alt attr. and finally strip html... */ 2245 sLoopData = mTypeData.replace(/\n/g," "); 2246 sLoopData = 2247 sLoopData.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi, 2248 '$1$2$3'); 2249 sLoopData = sLoopData.replace( /<.*?>/g, "" ); 2250 } 2251 else 2252 { 2253 sLoopData = mTypeData+""; 2254 } 2255 2256 /* Trim and clean the data */ 2257 sLoopData = sLoopData.replace(/^\s+/, '').replace(/\s+$/, ''); 2258 sLoopData = this._fnHtmlDecode( sLoopData ); 2259 2260 /* Bound it and add it to the total data */ 2261 aRow.push( this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) ); 2262 } 2263 } 2264 2265 aData.push( aRow.join(oConfig.sFieldSeperator) ); 2266 2267 /* Details rows from fnOpen */ 2268 if ( oConfig.bOpenRows ) 2269 { 2270 arr = $.grep(dt.aoOpenRows, function(o) { return o.nParent === tr; }); 2271 2272 if ( arr.length === 1 ) 2273 { 2274 sLoopData = this._fnBoundData( $('td', arr[0].nTr).html(), oConfig.sFieldBoundary, regex ); 2275 aData.push( sLoopData ); 2276 } 2277 } 2278 } 2279 2280 /* 2281 * Footer 2282 */ 2283 if ( oConfig.bFooter && dt.nTFoot !== null ) 2284 { 2285 aRow = []; 2286 2287 for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ ) 2288 { 2289 if ( aColumnsInc[i] && dt.aoColumns[i].nTf !== null ) 2290 { 2291 sLoopData = dt.aoColumns[i].nTf.innerHTML.replace(/\n/g," ").replace( /<.*?>/g, "" ); 2292 sLoopData = this._fnHtmlDecode( sLoopData ); 2293 2294 aRow.push( this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) ); 2295 } 2296 } 2297 2298 aData.push( aRow.join(oConfig.sFieldSeperator) ); 2299 } 2300 2301 var _sLastData = aData.join( this._fnNewline(oConfig) ); 2302 return _sLastData; 2303 }, 2304 2305 2306 /** 2307 * Wrap data up with a boundary string 2308 * @method _fnBoundData
2309 * @param {String} sData data to bound 2310 * @param {String} sBoundary bounding char(s) 2311 * @param {RegExp} regex search for the bounding chars - constructed outside for efficiency 2312 * in the loop 2313 * @returns {String} bound data 2314 * @private 2315 */ 2316 "_fnBoundData": function ( sData, sBoundary, regex ) 2317 { 2318 if ( sBoundary === "" ) 2319 { 2320 return sData; 2321 } 2322 else 2323 { 2324 return sBoundary + sData.replace(regex, sBoundary+sBoundary) + sBoundary; 2325 } 2326 }, 2327 2328 2329 /** 2330 * Break a string up into an array of smaller strings 2331 * @method _fnChunkData 2332 * @param {String} sData data to be broken up 2333 * @param {Int} iSize chunk size 2334 * @returns {Array} String array of broken up text 2335 * @private 2336 */ 2337 "_fnChunkData": function ( sData, iSize ) 2338 { 2339 var asReturn = []; 2340 var iStrlen = sData.length; 2341 2342 for ( var i=0 ; i<iStrlen ; i+=iSize ) 2343 { 2344 if ( i+iSize < iStrlen ) 2345 { 2346 asReturn.push( sData.substring( i, i+iSize ) ); 2347 } 2348 else 2349 { 2350 asReturn.push( sData.substring( i, iStrlen ) ); 2351 } 2352 } 2353 2354 return asReturn; 2355 }, 2356 2357 2358 /** 2359 * Decode HTML entities 2360 * @method _fnHtmlDecode 2361 * @param {String} sData encoded string 2362 * @returns {String} decoded string 2363 * @private 2364 */ 2365 "_fnHtmlDecode": function ( sData ) 2366 { 2367 if ( sData.indexOf('&') === -1 ) 2368 { 2369 return sData; 2370 } 2371 2372 var n = document.createElement('div'); 2373 2374 return sData.replace( /&([^\s]*?);/g, function( match, match2 ) { 2375 if ( match.substr(1, 1) === '#' ) 2376 { 2377 return String.fromCharCode( Number(match2.substr(1)) ); 2378 } 2379 else 2380 { 2381 n.innerHTML = match; 2382 return n.childNodes[0].nodeValue; 2383 } 2384 } ); 2385 }, 2386 2387 2388 2389 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2390 * Printing functions 2391 */ 2392 2393 /** 2394 * Show print display 2395 * @method _fnPrintStart 2396 * @param {Event} e Event object 2397 * @param {Object} oConfig Button configuration object 2398 * @returns void 2399 * @private 2400 */ 2401 "_fnPrintStart": function ( oConfig ) 2402 { 2403 var that = this; 2404 var oSetDT = this.s.dt; 2405 2406 /* Parse through the DOM hiding everything that isn't needed for the table */ 2407 this._fnPrintHideNodes( oSetDT.nTable ); 2408 2409 /* Show the whole table */ 2410 this.s.print.saveStart = oSetDT._iDisplayStart; 2411 this.s.print.saveLength = oSetDT._iDisplayLength; 2412 2413 if ( oConfig.bShowAll ) 2414 { 2415 oSetDT._iDisplayStart = 0; 2416 oSetDT._iDisplayLength = -1; 2417 if ( oSetDT.oApi._fnCalculateEnd ) { 2418 oSetDT.oApi._fnCalculateEnd( oSetDT ); 2419 } 2420 oSetDT.oApi._fnDraw( oSetDT ); 2421 } 2422 2423 /* Adjust the display for scrolling which might be done by DataTables */ 2424 if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" ) 2425 { 2426 this._fnPrintScrollStart( oSetDT ); 2427 2428 // If the table redraws while in print view, the DataTables scrolling 2429 // setup would hide the header, so we need to readd it on draw 2430 $(this.s.dt.nTable).bind('draw.DTTT_Print', function () { 2431 that._fnPrintScrollStart( oSetDT ); 2432 } ); 2433 } 2434 2435 /* Remove the other DataTables feature nodes - but leave the table! and info div */ 2436 var anFeature = oSetDT.aanFeatures; 2437 for ( var cFeature in anFeature ) 2438 { 2439 if ( cFeature != 'i' && cFeature != 't' && cFeature.length == 1 ) 2440 { 2441 for ( var i=0, iLen=anFeature[cFeature].length ; i<iLen ; i++ ) 2442 { 2443 this.dom.print.hidden.push( { 2444 "node": anFeature[cFeature][i], 2445 "display": "block" 2446 } ); 2447 anFeature[cFeature][i].style.display = "none"; 2448 } 2449 } 2450 } 2451 2452 /* Print class can be used for styling */ 2453 $(document.body).addClass( this.classes.print.body ); 2454 2455 /* Show information message to let the user know what is happening */ 2456 if ( oConfig.sInfo !== "" ) 2457 { 2458 this.fnInfo( oConfig.sInfo, 3000 ); 2459 } 2460 2461 /* Add a message at the top of the page */ 2462 if ( oConfig.sMessage ) 2463 { 2464 $('<div/>') 2465 .addClass( this.classes.print.message ) 2466 .html( oConfig.sMessage ) 2467 .prependTo( 'body' ); 2468 } 2469 2470 /* Cache the scrolling and the jump to the top of the page */ 2471 this.s.print.saveScroll = $(window).scrollTop(); 2472 window.scrollTo( 0, 0 ); 2473 2474 /* Bind a key event listener to the document for the escape key - 2475 * it is removed in the callback 2476 */ 2477 $(document).bind( "keydown.DTTT", function(e) { 2478 /* Only interested in the escape key */ 2479 if ( e.keyCode == 27 ) 2480 { 2481 e.preventDefault(); 2482 that._fnPrintEnd.call( that, e ); 2483 } 2484 } ); 2485 }, 2486 2487 2488 /** 2489 * Printing is finished, resume normal display 2490 * @method _fnPrintEnd 2491 * @param {Event} e Event object 2492 * @returns void 2493 * @private 2494 */ 2495 "_fnPrintEnd": function ( e ) 2496 { 2497 var that = this; 2498 var oSetDT = this.s.dt; 2499 var oSetPrint = this.s.print; 2500 var oDomPrint = this.dom.print; 2501 2502 /* Show all hidden nodes */ 2503 this._fnPrintShowNodes(); 2504 2505 /* Restore DataTables' scrolling */ 2506 if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" ) 2507 { 2508 $(this.s.dt.nTable).unbind('draw.DTTT_Print'); 2509 2510 this._fnPrintScrollEnd(); 2511 } 2512 2513 /* Restore the scroll */ 2514 window.scrollTo( 0, oSetPrint.saveScroll ); 2515 2516 /* Drop the print message */ 2517 $('div.'+this.classes.print.message).remove(); 2518 2519 /* Styling class */ 2520 $(document.body).removeClass( 'DTTT_Print' ); 2521 2522 /* Restore the table length */ 2523 oSetDT._iDisplayStart = oSetPrint.saveStart; 2524 oSetDT._iDisplayLength = oSetPrint.saveLength; 2525 if ( oSetDT.oApi._fnCalculateEnd ) { 2526 oSetDT.oApi._fnCalculateEnd( oSetDT ); 2527 } 2528 oSetDT.oApi._fnDraw( oSetDT ); 2529 2530 $(document).unbind( "keydown.DTTT" ); 2531 }, 2532 2533 2534 /** 2535 * Take account of scrolling in DataTables by showing the full table 2536 * @returns void 2537 * @private 2538 */ 2539 "_fnPrintScrollStart": function () 2540 { 2541 var 2542 oSetDT = this.s.dt, 2543 nScrollHeadInner = oSetDT.nScrollHead.getElementsByTagName('div')[0], 2544 nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], 2545 nScrollBody = oSetDT.nTable.parentNode, 2546 nTheadSize, nTfootSize; 2547 2548 /* Copy the header in the thead in the body table, this way we show one single table when 2549 * in print view. Note that this section of code is more or less verbatim from DT 1.7.0 2550 */ 2551 nTheadSize = oSetDT.nTable.getElementsByTagName('thead'); 2552 if ( nTheadSize.length > 0 ) 2553 { 2554 oSetDT.nTable.removeChild( nTheadSize[0] ); 2555 } 2556 2557 if ( oSetDT.nTFoot !== null ) 2558 { 2559 nTfootSize = oSetDT.nTable.getElementsByTagName('tfoot'); 2560 if ( nTfootSize.length > 0 ) 2561 { 2562 oSetDT.nTable.removeChild( nTfootSize[0] ); 2563 } 2564 } 2565 2566 nTheadSize = oSetDT.nTHead.cloneNode(true); 2567 oSetDT.nTable.insertBefore( nTheadSize, oSetDT.nTable.childNodes[0] ); 2568 2569 if ( oSetDT.nTFoot !== null ) 2570 { 2571 nTfootSize = oSetDT.nTFoot.cloneNode(true); 2572 oSetDT.nTable.insertBefore( nTfootSize, oSetDT.nTable.childNodes[1] ); 2573 } 2574 2575 /* Now adjust the table's viewport so we can actually see it */ 2576 if ( oSetDT.oScroll.sX !== "" ) 2577 { 2578 oSetDT.nTable.style.width = $(oSetDT.nTable).outerWidth()+"px"; 2579 nScrollBody.style.width = $(oSetDT.nTable).outerWidth()+"px"; 2580 nScrollBody.style.overflow = "visible"; 2581 } 2582 2583 if ( oSetDT.oScroll.sY !== "" ) 2584 { 2585 nScrollBody.style.height = $(oSetDT.nTable).outerHeight()+"px"; 2586 nScrollBody.style.overflow = "visible"; 2587 } 2588 }, 2589 2590 2591 /** 2592 * Take account of scrolling in DataTables by showing the full table. Note that the redraw of 2593 * the DataTable that we do will actually deal with the majority of the hard
2593work here 2594 * @returns void 2595 * @private 2596 */ 2597 "_fnPrintScrollEnd": function () 2598 { 2599 var 2600 oSetDT = this.s.dt, 2601 nScrollBody = oSetDT.nTable.parentNode; 2602 2603 if ( oSetDT.oScroll.sX !== "" ) 2604 { 2605 nScrollBody.style.width = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sX ); 2606 nScrollBody.style.overflow = "auto"; 2607 } 2608 2609 if ( oSetDT.oScroll.sY !== "" ) 2610 { 2611 nScrollBody.style.height = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sY ); 2612 nScrollBody.style.overflow = "auto"; 2613 } 2614 }, 2615 2616 2617 /** 2618 * Resume the display of all TableTools hidden nodes 2619 * @method _fnPrintShowNodes 2620 * @returns void 2621 * @private 2622 */ 2623 "_fnPrintShowNodes": function ( ) 2624 { 2625 var anHidden = this.dom.print.hidden; 2626 2627 for ( var i=0, iLen=anHidden.length ; i<iLen ; i++ ) 2628 { 2629 anHidden[i].node.style.display = anHidden[i].display; 2630 } 2631 anHidden.splice( 0, anHidden.length ); 2632 }, 2633 2634 2635 /** 2636 * Hide nodes which are not needed in order to display the table. Note that this function is 2637 * recursive 2638 * @method _fnPrintHideNodes 2639 * @param {Node} nNode Element which should be showing in a 'print' display 2640 * @returns void 2641 * @private 2642 */ 2643 "_fnPrintHideNodes": function ( nNode ) 2644 { 2645 var anHidden = this.dom.print.hidden; 2646 2647 var nParent = nNode.parentNode; 2648 var nChildren = nParent.childNodes; 2649 for ( var i=0, iLen=nChildren.length ; i<iLen ; i++ ) 2650 { 2651 if ( nChildren[i] != nNode && nChildren[i].nodeType == 1 ) 2652 { 2653 /* If our node is shown (don't want to show nodes which were previously hidden) */ 2654 var sDisplay = $(nChildren[i]).css("display"); 2655 if ( sDisplay != "none" ) 2656 { 2657 /* Cache the node and it's previous state so we can restore it */ 2658 anHidden.push( { 2659 "node": nChildren[i], 2660 "display": sDisplay 2661 } ); 2662 nChildren[i].style.display = "none"; 2663 } 2664 } 2665 } 2666 2667 if ( nParent.nodeName.toUpperCase() != "BODY" ) 2668 { 2669 this._fnPrintHideNodes( nParent ); 2670 } 2671 } 2672}; 2673 2674 2675 2676/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2677 * Static variables 2678 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2679 2680/** 2681 * Store of all instances that have been created of TableTools, so one can look up other (when 2682 * there is need of a master) 2683 * @property _aInstances 2684 * @type Array 2685 * @default [] 2686 * @private 2687 */ 2688TableTools._aInstances = []; 2689 2690 2691/** 2692 * Store of all listeners and their callback functions 2693 * @property _aListeners 2694 * @type Array 2695 * @default [] 2696 */ 2697TableTools._aListeners = []; 2698 2699 2700 2701/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2702 * Static methods 2703 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2704 2705/** 2706 * Get an array of all the master instances 2707 * @method fnGetMasters 2708 * @returns {Array} List of master TableTools instances 2709 * @static 2710 */ 2711TableTools.fnGetMasters = function () 2712{ 2713 var a = []; 2714 for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ ) 2715 { 2716 if ( TableTools._aInstances[i].s.master ) 2717 { 2718 a.push( TableTools._aInstances[i] ); 2719 } 2720 } 2721 return a; 2722}; 2723 2724/** 2725 * Get the master instance for a table node (or id if a string is given) 2726 * @method fnGetInstance 2727 * @returns {Object} ID of table OR table node, for which we want the TableTools instance 2728 * @static 2729 */ 2730TableTools.fnGetInstance = function ( node ) 2731{ 2732 if ( typeof node != 'object' ) 2733 { 2734 node = document.getElementById(node); 2735 } 2736 2737 for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ ) 2738 { 2739 if ( TableTools._aInstances[i].s.master && TableTools._aInstances[i].dom.table == node ) 2740 { 2741 return TableTools._aInstances[i]; 2742 } 2743 } 2744 return null; 2745}; 2746 2747 2748/** 2749 * Add a listener for a specific event 2750 * @method _fnEventListen 2751 * @param {Object} that Scope of the listening function (i.e. 'this' in the caller) 2752 * @param {String} type Event type 2753 * @param {Function} fn Function 2754 * @returns void 2755 * @private 2756 * @static 2757 */ 2758TableTools._fnEventListen = function ( that, type, fn ) 2759{ 2760 TableTools._aListeners.push( { 2761 "that": that, 2762 "type": type, 2763 "fn": fn 2764 } ); 2765}; 2766 2767 2768/** 2769 * An event has occurred - look up every listener and fire it off. We check that the event we are 2770 * going to fire is attached to the same table (using the table node as reference) before firing 2771 * @method _fnEventDispatch 2772 * @param {Object} that Scope of the listening function (i.e. 'this' in the caller)
2773 * @param {String} type Event type 2774 * @param {Node} node Element that the event occurred on (may be null) 2775 * @param {boolean} [selected] Indicate if the node was selected (true) or deselected (false) 2776 * @returns void 2777 * @private 2778 * @static 2779 */ 2780TableTools._fnEventDispatch = function ( that, type, node, selected ) 2781{ 2782 var listeners = TableTools._aListeners; 2783 for ( var i=0, iLen=listeners.length ; i<iLen ; i++ ) 2784 { 2785 if ( that.dom.table == listeners[i].that.dom.table && listeners[i].type == type ) 2786 { 2787 listeners[i].fn( node, selected ); 2788 } 2789 } 2790}; 2791 2792 2793 2794 2795 2796 2797/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 2798 * Constants 2799 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2800 2801 2802 2803TableTools.buttonBase = { 2804 // Button base 2805 "sAction": "text", 2806 "sTag": "default", 2807 "sLinerTag": "default", 2808 "sButtonClass": "DTTT_button_text", 2809 "sButtonText": "Button text", 2810 "sTitle": "", 2811 "sToolTip": "", 2812 2813 // Common button specific options 2814 "sCharSet": "utf8", 2815 "bBomInc": false, 2816 "sFileName": "*.csv", 2817 "sFieldBoundary": "", 2818 "sFieldSeperator": "\t", 2819 "sNewLine": "auto", 2820 "mColumns": "all", /* "all", "visible", "hidden" or array of column integers */ 2821 "bHeader": true, 2822 "bFooter": true, 2823 "bOpenRows": false, 2824 "bSelectedOnly": false, 2825 "oSelectorOpts": undefined, // See http://datatables.net/docs/DataTables/1.9.4/#$ for full options 2826 2827 // Callbacks 2828 "fnMouseover": null, 2829 "fnMouseout": null, 2830 "fnClick": null, 2831 "fnSelect": null, 2832 "fnComplete": null, 2833 "fnInit": null, 2834 "fnCellRender": null 2835}; 2836 2837 2838/** 2839 * @namespace Default button configurations 2840 */ 2841TableTools.BUTTONS = { 2842 "csv": $.extend( {}, TableTools.buttonBase, { 2843 "sAction": "flash_save", 2844 "sButtonClass": "DTTT_button_csv", 2845 "sButtonText": "CSV", 2846 "sFieldBoundary": '"', 2847 "sFieldSeperator": ",", 2848 "fnClick": function( nButton, oConfig, flash ) { 2849 this.fnSetText( flash, this.fnGetTableData(oConfig) ); 2850 } 2851 } ), 2852 2853 "xls": $.extend( {}, TableTools.buttonBase, { 2854 "sAction": "flash_save", 2855 "sCharSet": "utf16le", 2856 "bBomInc": true, 2857 "sButtonClass": "DTTT_button_xls", 2858 "sButtonText": "Excel", 2859 "fnClick": function( nButton, oConfig, flash ) { 2860 this.fnSetText( flash, this.fnGetTableData(oConfig) ); 2861 } 2862 } ), 2863 2864 "copy": $.extend( {}, TableTools.buttonBase, { 2865 "sAction": "flash_copy", 2866 "sButtonClass": "DTTT_button_copy", 2867 "sButtonText": "Copy", 2868 "fnClick": function( nButton, oConfig, flash ) { 2869 this.fnSetText( flash, this.fnGetTableData(oConfig) ); 2870 }, 2871 "fnComplete": function(nButton, oConfig, flash, text) { 2872 var lines = text.split('\n').length; 2873 if (oConfig.bHeader) lines--; 2874 if (this.s.dt.nTFoot !== null && oConfig.bFooter) lines--; 2875 var plural = (lines==1) ? "" : "s"; 2876 this.fnInfo( '<h6>Table copied</h6>'+ 2877 '<p>Copied '+lines+' row'+plural+' to the clipboard.</p>', 2878 1500 2879 ); 2880 } 2881 } ), 2882 2883 "pdf": $.extend( {}, TableTools.buttonBase, { 2884 "sAction": "flash_pdf", 2885 "sNewLine": "\n", 2886 "sFileName": "*.pdf", 2887 "sButtonClass": "DTTT_button_pdf", 2888 "sButtonText": "PDF", 2889 "sPdfOrientation": "portrait", 2890 "sPdfSize": "A4", 2891 "sPdfMessage": "", 2892 "fnClick": function( nButton, oConfig, flash ) { 2893 this.fnSetText( flash, 2894 "title:"+ this.fnGetTitle(oConfig) +"\n"+ 2895 "message:"+ oConfig.sPdfMessage +"\n"+ 2896 "colWidth:"+ this.fnCalcColRatios(oConfig) +"\n"+ 2897 "orientation:"+ oConfig.sPdfOrientation +"\n"+ 2898 "size:"+ oConfig.sPdfSize +"\n"+ 2899 "--/TableToolsOpts--\n" + 2900 this.fnGetTableData(oConfig) 2901 ); 2902 } 2903 } ), 2904 2905 "print": $.extend( {}, TableTools.buttonBase, { 2906 "sInfo": "<h6>Print view</h6><p>Please use your browser's print function to "+ 2907 "print this table. Press escape when finished.</p>", 2908 "sMessage": null, 2909 "bShowAll": true, 2910 "sToolTip": "View print view", 2911 "sButtonClass": "DTTT_button_print", 2912 "sButtonText": "Print", 2913 "fnClick": function ( nButton, oConfig ) { 2914 this.fnPrint( true, oConfig ); 2915 } 2916 } ), 2917 2918 "text": $.extend( {}, TableTools.buttonBase ), 2919 2920 "select": $.extend( {}, TableTools.buttonBase, { 2921 "sButtonText": "Select button", 2922 "fnSelect": function( nButton, oConfig ) { 2923 if ( this.fnGetSelected().length !== 0 ) { 2924 $(nButton).removeClass( this.classes.buttons.disabled ); 2925 } else { 2926 $(nButton).addClass( this.classes.buttons.disabled ); 2927 } 2928 }, 2929 "fnInit": function( nButton, oConfig ) { 2930 $(nButton).addClass( this.classes.buttons.disabled ); 2931 } 2932 } ), 2933 2934 "select_single": $.extend( {}, TableTools.buttonBase, { 2935 "sButtonText": "Select button", 2936 "fnSelect": function( nButton, oConfig ) { 2937 var iSelected = this.fnGetSelected().length; 2938 if ( iSelected == 1 ) { 2939 $(nButton).removeClass( this.classes.buttons.disabled ); 2940 } else { 2941 $(nButton).addClass( this.classes.buttons.disabled ); 2942 } 2943 }, 2944 "fnInit": function( nButton, oConfig ) { 2945 $(nButton).addClass( this.classes.buttons.disabled ); 2946 } 2947 } ), 2948 2949 "select_all": $.extend( {}, TableTools.buttonBase, { 2950 "sButtonText": "Select all", 2951 "fnClick": function( nButton, oConfig ) { 2952 this.fnSelectAll(); 2953 }, 2954 "fnSelect": function( nButton, oConfig ) { 2955 if ( this.fnGetSelected().length == this.s.dt.fnRecordsDisplay() ) { 2956 $(nButton).addClass( this.classes.buttons.disabled ); 2957 } else { 2958 $(nButton).removeClass( this.classes.buttons.disabled ); 2959 } 2960 } 2961 } ), 2962 2963 "select_none": $.extend( {}, TableTools.buttonBase, { 2964 "sButtonText": "Deselect all", 2965 "fnClick": function( nButton, oConfig ) { 2966 this.fnSelectNone(); 2967 }, 2968 "fnSelect": function( nButton, oConfig ) { 2969 if ( this.fnGetSelected().length !== 0 ) { 2970 $(nButton).removeClass( this.classes.buttons.disabled ); 2971 } else { 2972 $(nButton).addClass( this.classes.buttons.disabled ); 2973 } 2974 }, 2975 "fnInit": function( nButton, oConfig ) { 2976 $(nButton).addClass( this.classes.buttons.disabled ); 2977 } 2978 } ), 2979 2980 "ajax": $.extend( {}, TableTools.buttonBase, { 2981 "sAjaxUrl": "/xhr.php", 2982 "sButtonText": "Ajax button", 2983 "fnClick": function( nButton, oConfig ) { 2984 var sData = this.fnGetTableData(oConfig); 2985 $.ajax( { 2986 "url": oConfig.sAjaxUrl, 2987 "data": [ 2988 { "name": "tableData", "value": sData } 2989 ], 2990 "success": oConfig.fnAjaxComplete, 2991 "dataType": "json", 2992 "type": "POST", 2993 "cache": false, 2994 "error": function () { 2995 alert( "Error detected when sending table data to server" ); 2996 } 2997 } ); 2998 }, 2999 "fnAjaxComplete": function( json ) { 3000 alert( 'Ajax complete' ); 3001 } 3002 } ), 3003 3004 "div": $.extend( {}, TableTools.buttonBase, { 3005 "sAction": "div", 3006 "sTag": "div", 3007 "sButtonClass": "DTTT_nonbutton", 3008 "sButtonText": "Text button" 3009 } ), 3010 3011 "collection": $.extend( {}, TableTools.buttonBase, { 3012 "sAction": "collection", 3013 "sButtonClass": "DTTT_button_collection", 3014 "sButtonText": "Collection", 3015 "fnClick": function( nButton, oConfig ) { 3016 this._fnCollectionShow(nButton, oConfig); 3017 } 3018 } ) 3019}; 3020/* 3021 * on* callback parameters: 3022 * 1. node - button element 3023 * 2. object - configuration object for this button 3024 * 3. object - ZeroClipboard reference (flash button only) 3025 * 4. string - Returned string from Flash (flash button only - and only on 'complete') 3026 */ 3027 3028// Alias to match the other plug-ins styling 3029TableTools.buttons = TableTools.BUTTONS; 3030 3031 3032/** 3033 * @namespace Classes used by TableTools - allows the styles to be override easily. 3034 * Note that when TableTools initialises it will take a copy of the classes object
3035 * and will use its internal copy for the remainder of its run time. 3036 */ 3037TableTools.classes = { 3038 "container": "DTTT_container", 3039 "buttons": { 3040 "normal": "DTTT_button", 3041 "disabled": "DTTT_disabled" 3042 }, 3043 "collection": { 3044 "container": "DTTT_collection", 3045 "background": "DTTT_collection_background", 3046 "buttons": { 3047 "normal": "DTTT_button", 3048 "disabled": "DTTT_disabled" 3049 } 3050 }, 3051 "select": { 3052 "table": "DTTT_selectable", 3053 "row": "DTTT_selected selected" 3054 }, 3055 "print": { 3056 "body": "DTTT_Print", 3057 "info": "DTTT_print_info", 3058 "message": "DTTT_PrintMessage" 3059 } 3060}; 3061 3062 3063/** 3064 * @namespace ThemeRoller classes - built in for compatibility with DataTables' 3065 * bJQueryUI option. 3066 */ 3067TableTools.classes_themeroller = { 3068 "container": "DTTT_container ui-buttonset ui-buttonset-multi", 3069 "buttons": { 3070 "normal": "DTTT_button ui-button ui-state-default" 3071 }, 3072 "collection": { 3073 "container": "DTTT_collection ui-buttonset ui-buttonset-multi" 3074 } 3075}; 3076 3077 3078/** 3079 * @namespace TableTools default settings for initialisation 3080 */ 3081TableTools.DEFAULTS = { 3082 "sSwfPath": "../swf/copy_csv_xls_pdf.swf", 3083 "sRowSelect": "none", 3084 "sRowSelector": "tr", 3085 "sSelectedClass": null, 3086 "fnPreRowSelect": null, 3087 "fnRowSelected": null, 3088 "fnRowDeselected": null, 3089 "aButtons": [ "copy", "csv", "xls", "pdf", "print" ], 3090 "oTags": { 3091 "container": "div", 3092 "button": "a", // We really want to use buttons here, but Firefox and IE ignore the 3093 // click on the Flash element in the button (but not mouse[in|out]). 3094 "liner": "span", 3095 "collection": { 3096 "container": "div", 3097 "button": "a", 3098 "liner": "span" 3099 } 3100 } 3101}; 3102 3103// Alias to match the other plug-ins 3104TableTools.defaults = TableTools.DEFAULTS; 3105 3106 3107/** 3108 * Name of this class 3109 * @constant CLASS 3110 * @type String 3111 * @default TableTools 3112 */ 3113TableTools.prototype.CLASS = "TableTools"; 3114 3115 3116/** 3117 * TableTools version 3118 * @constant VERSION 3119 * @type String 3120 * @default See code 3121 */ 3122TableTools.version = "2.2.4"; 3123 3124 3125 3126// DataTables 1.10 API 3127// 3128// This will be extended in a big way in in TableTools 3 to provide API methods 3129// such as rows().select() and rows.selected() etc, but for the moment the 3130// tabletools() method simply returns the instance. 3131 3132if ( $.fn.dataTable.Api ) { 3133 $.fn.dataTable.Api.register( 'tabletools()', function () { 3134 var tt = null; 3135 3136 if ( this.context.length > 0 ) { 3137 tt = TableTools.fnGetInstance( this.context[0].nTable ); 3138 } 3139 3140 return tt; 3141 } ); 3142} 3143 3144 3145 3146 3147/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3148 * Initialisation 3149 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 3150 3151/* 3152 * Register a new feature with DataTables 3153 */ 3154if ( typeof $.fn.dataTable == "function" && 3155 typeof $.fn.dataTableExt.fnVersionCheck == "function" && 3156 $.fn.dataTableExt.fnVersionCheck('1.9.0') ) 3157{ 3158 $.fn.dataTableExt.aoFeatures.push( { 3159 "fnInit": function( oDTSettings ) { 3160 var init = oDTSettings.oInit; 3161 var opts = init ? 3162 init.tableTools || init.oTableTools || {} : 3163 {}; 3164 3165 return new TableTools( oDTSettings.oInstance, opts ).dom.container; 3166 }, 3167 "cFeature": "T", 3168 "sFeature": "TableTools" 3169 } ); 3170} 3171else 3172{ 3173 alert( "Warning: TableTools requires DataTables 1.9.0 or newer - www.datatables.net/download"); 3174} 3175 3176$.fn.DataTable.TableTools = TableTools; 3177 3178})(jQuery, window, document); 3179 3180/* 3181 * Register a new feature with DataTables 3182 */ 3183if ( typeof $.fn.dataTable == "function" && 3184 typeof $.fn.dataTableExt.fnVersionCheck == "function" && 3185 $.fn.dataTableExt.fnVersionCheck('1.9.0') ) 3186{ 3187 $.fn.dataTableExt.aoFeatures.push( { 3188 "fnInit": function( oDTSettings ) { 3189 var oOpts = typeof oDTSettings.oInit.oTableTools != 'undefined' ? 3190 oDTSettings.oInit.oTableTools : {}; 3191 3192 var oTT = new TableTools( oDTSettings.oInstance, oOpts ); 3193 TableTools._aInstances.push( oTT ); 3194 3195 return oTT.dom.container; 3196 }, 3197 "cFeature": "T", 3198 "sFeature": "TableTools" 3199 } ); 3200} 3201else 3202{ 3203 alert( "Warning: TableTools 2 requires DataTables 1.9.0 or newer - www.datatables.net/download"); 3204} 3205 3206 3207$.fn.dataTable.TableTools = TableTools; 3208$.fn.DataTable.TableTools = TableTools; 3209 3210 3211return TableTools; 3212}; // /factory 3213 3214 3215// Define as an AMD module if possible 3216if ( typeof define === 'function' && define.amd ) { 3217 define( ['jquery', 'datatables'], factory ); 3218} 3219else if ( typeof exports === 'object' ) { 3220 // Node/CommonJS 3221 factory( require('jquery'), require('datatables') ); 3222} 3223else if ( jQuery && !jQuery.fn.dataTable.TableTools ) { 3224 // Otherwise simply initialise as normal, stopping multiple evaluation 3225 factory( jQuery, jQuery.fn.dataTable ); 3226} 3227 3228 3229})(window, document); 3230
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.