]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/static/AdminLTE-2.3.7/plugins/datatables/extensions/TableTools/js/dataTables.tableTools.js
update sources to v12.1.0
[ceph.git] / ceph / src / pybind / mgr / dashboard / static / AdminLTE-2.3.7 / plugins / datatables / extensions / TableTools / js / dataTables.tableTools.js
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 */
31 var TableTools;
32
33 (function(window, document, undefined) {
34
35
36 var factory = function( $, DataTable ) {
37 "use strict";
38
39
40 //include ZeroClipboard.js
41 /* ZeroClipboard 1.0.4
42 * Author: Joseph Huckaby
43 */
44
45 var ZeroClipboard_TableTools = {
46
47 version: "1.0.4-TableTools2",
48 clients: {}, // registered upload clients on page, indexed by id
49 moviePath: '', // URL to movie
50 nextId: 1, // ID of next movie
51
52 $: function(thingy) {
53 // simple DOM lookup utility function
54 if (typeof(thingy) == 'string') {
55 thingy = document.getElementById(thingy);
56 }
57 if (!thingy.addClass) {
58 // extend element with a few useful methods
59 thingy.hide = function() { this.style.display = 'none'; };
60 thingy.show = function() { this.style.display = ''; };
61 thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
62 thingy.removeClass = function(name) {
63 this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
64 };
65 thingy.hasClass = function(name) {
66 return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
67 };
68 }
69 return thingy;
70 },
71
72 setMoviePath: function(path) {
73 // set path to ZeroClipboard.swf
74 this.moviePath = path;
75 },
76
77 dispatch: function(id, eventName, args) {
78 // receive event from flash movie, send to client
79 var client = this.clients[id];
80 if (client) {
81 client.receiveEvent(eventName, args);
82 }
83 },
84
85 register: function(id, client) {
86 // register new client to receive events
87 this.clients[id] = client;
88 },
89
90 getDOMObjectPosition: function(obj) {
91 // get absolute coordinates for dom element
92 var info = {
93 left: 0,
94 top: 0,
95 width: obj.width ? obj.width : obj.offsetWidth,
96 height: obj.height ? obj.height : obj.offsetHeight
97 };
98
99 if ( obj.style.width !== "" ) {
100 info.width = obj.style.width.replace("px","");
101 }
102
103 if ( obj.style.height !== "" ) {
104 info.height = obj.style.height.replace("px","");
105 }
106
107 while (obj) {
108 info.left += obj.offsetLeft;
109 info.top += obj.offsetTop;
110 obj = obj.offsetParent;
111 }
112
113 return info;
114 },
115
116 Client: function(elem) {
117 // constructor for new simple upload client
118 this.handlers = {};
119
120 // unique ID
121 this.id = ZeroClipboard_TableTools.nextId++;
122 this.movieId = 'ZeroClipboard_TableToolsMovie_' + this.id;
123
124 // register client with singleton to receive flash events
125 ZeroClipboard_TableTools.register(this.id, this);
126
127 // create movie
128 if (elem) {
129 this.glue(elem);
130 }
131 }
132 };
133
134 ZeroClipboard_TableTools.Client.prototype = {
135
136 id: 0, // unique ID for us
137 ready: false, // whether movie is ready to receive events or not
138 movie: null, // reference to movie object
139 clipText: '', // text to copy to clipboard
140 fileName: '', // default file save name
141 action: 'copy', // action to perform
142 handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
143 cssEffects: true, // enable CSS mouse effects on dom container
144 handlers: null, // user event handlers
145 sized: false,
146
147 glue: function(elem, title) {
148 // glue to DOM element
149 // elem can be ID or actual DOM element object
150 this.domElement = ZeroClipboard_TableTools.$(elem);
151
152 // float just above object, or zIndex 99 if dom element isn't set
153 var zIndex = 99;
154 if (this.domElement.style.zIndex) {
155 zIndex = parseInt(this.domElement.style.zIndex, 10) + 1;
156 }
157
158 // find X/Y position of domElement
159 var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
160
161 // create floating DIV above element
162 this.div = document.createElement('div');
163 var style = this.div.style;
164 style.position = 'absolute';
165 style.left = '0px';
166 style.top = '0px';
167 style.width = (box.width) + 'px';
168 style.height = box.height + 'px';
169 style.zIndex = zIndex;
170
171 if ( typeof title != "undefined" && title !== "" ) {
172 this.div.title = title;
173 }
174 if ( box.width !== 0 && box.height !== 0 ) {
175 this.sized = true;
176 }
177
178 // style.backgroundColor = '#f00'; // debug
179 if ( this.domElement ) {
180 this.domElement.appendChild(this.div);
181 this.div.innerHTML = this.getHTML( box.width, box.height ).replace(/&/g, '&');
182 }
183 },
184
185 positionElement: function() {
186 var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
187 var style = this.div.style;
188
189 style.position = 'absolute';
190 //style.left = (this.domElement.offsetLeft)+'px';
191 //style.top = this.domElement.offsetTop+'px';
192 style.width = box.width + 'px';
193 style.height = box.height + 'px';
194
195 if ( box.width !== 0 && box.height !== 0 ) {
196 this.sized = true;
197 } else {
198 return;
199 }
200
201 var flash = this.div.childNodes[0];
202 flash.width = box.width;
203 flash.height = box.height;
204 },
205
206 getHTML: function(width, height) {
207 // return HTML for movie
208 var html = '';
209 var flashvars = 'id=' + this.id +
210 '&width=' + width +
211 '&height=' + height;
212
213 if (navigator.userAgent.match(/MSIE/)) {
214 // IE gets an OBJECT tag
215 var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
216 html += '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=10,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard_TableTools.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
217 }
218 else {
219 // all other browsers get an EMBED tag
220 html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard_TableTools.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
221 }
222 return html;
223 },
224
225 hide: function() {
226 // temporarily hide floater offscreen
227 if (this.div) {
228 this.div.style.left = '-2000px';
229 }
230 },
231
232 show: function() {
233 // show ourselves after a call to hide()
234 this.reposition();
235 },
236
237 destroy: function() {
238 // destroy control and floater
239 if (this.domElement && this.div) {
240 this.hide();
241 this.div.innerHTML = '';
242
243 var body = document.getElementsByTagName('body')[0];
244 try { body.removeChild( this.div ); } catch(e) {}
245
246 this.domElement = null;
247 this.div = null;
248 }
249 },
250
251 reposition: function(elem) {
252 // reposition our floating div, optionally to new container
253 // warning: container CANNOT change size, only position
254 if (elem) {
255 this.domElement = ZeroClipboard_TableTools.$(elem);
256 if (!this.domElement) {
257 this.hide();
258 }
259 }
260
261 if (this.domElement && this.div) {
262 var box = ZeroClipboard_TableTools.getDOMObjectPosition(this.domElement);
263 var style = this.div.style;
264 style.left = '' + box.left + 'px';
265 style.top = '' + box.top + 'px';
266 }
267 },
268
269 clearText: function() {
270 // clear the text to be copy / saved
271 this.clipText = '';
272 if (this.ready) {
273 this.movie.clearText();
274 }
275 },
276
277 appendText: function(newText) {
278 // append text to that which is to be copied / saved
279 this.clipText += newText;
280 if (this.ready) { this.movie.appendText(newText) ;}
281 },
282
283 setText: function(newText) {
284 // set text to be copied to be copied / saved
285 this.clipText = newText;
286 if (this.ready) { this.movie.setText(newText) ;}
287 },
288
289 setCharSet: function(charSet) {
290 // set the character set (UTF16LE or UTF8)
291 this.charSet = charSet;
292 if (this.ready) { this.movie.setCharSet(charSet) ;}
293 },
294
295 setBomInc: function(bomInc) {
296 // set if the BOM should be included or not
297 this.incBom = bomInc;
298 if (this.ready) { this.movie.setBomInc(bomInc) ;}
299 },
300
301 setFileName: function(newText) {
302 // set the file name
303 this.fileName = newText;
304 if (this.ready) {
305 this.movie.setFileName(newText);
306 }
307 },
308
309 setAction: function(newText) {
310 // set action (save or copy)
311 this.action = newText;
312 if (this.ready) {
313 this.movie.setAction(newText);
314 }
315 },
316
317 addEventListener: function(eventName, func) {
318 // add user event listener for event
319 // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
320 eventName = eventName.toString().toLowerCase().replace(/^on/, '');
321 if (!this.handlers[eventName]) {
322 this.handlers[eventName] = [];
323 }
324 this.handlers[eventName].push(func);
325 },
326
327 setHandCursor: function(enabled) {
328 // enable hand cursor (true), or default arrow cursor (false)
329 this.handCursorEnabled = enabled;
330 if (this.ready) {
331 this.movie.setHandCursor(enabled);
332 }
333 },
334
335 setCSSEffects: function(enabled) {
336 // enable or disable CSS effects on DOM container
337 this.cssEffects = !!enabled;
338 },
339
340 receiveEvent: function(eventName, args) {
341 var self;
342
343 // receive event from flash
344 eventName = eventName.toString().toLowerCase().replace(/^on/, '');
345
346 // special behavior for certain events
347 switch (eventName) {
348 case 'load':
349 // movie claims it is ready, but in IE this isn't always the case...
350 // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
351 this.movie = document.getElementById(this.movieId);
352 if (!this.movie) {
353 self = this;
354 setTimeout( function() { self.receiveEvent('load', null); }, 1 );
355 return;
356 }
357
358 // firefox on pc needs a "kick" in order to set these in certain cases
359 if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
360 self = this;
361 setTimeout( function() { self.receiveEvent('load', null); }, 100 );
362 this.ready = true;
363 return;
364 }
365
366 this.ready = true;
367 this.movie.clearText();
368 this.movie.appendText( this.clipText );
369 this.movie.setFileName( this.fileName );
370 this.movie.setAction( this.action );
371 this.movie.setCharSet( this.charSet );
372 this.movie.setBomInc( this.incBom );
373 this.movie.setHandCursor( this.handCursorEnabled );
374 break;
375
376 case 'mouseover':
377 if (this.domElement && this.cssEffects) {
378 //this.domElement.addClass('hover');
379 if (this.recoverActive) {
380 this.domElement.addClass('active');
381 }
382 }
383 break;
384
385 case 'mouseout':
386 if (this.domElement && this.cssEffects) {
387 this.recoverActive = false;
388 if (this.domElement.hasClass('active')) {
389 this.domElement.removeClass('active');
390 this.recoverActive = true;
391 }
392 //this.domElement.removeClass('hover');
393 }
394 break;
395
396 case 'mousedown':
397 if (this.domElement && this.cssEffects) {
398 this.domElement.addClass('active');
399 }
400 break;
401
402 case 'mouseup':
403 if (this.domElement && this.cssEffects) {
404 this.domElement.removeClass('active');
405 this.recoverActive = false;
406 }
407 break;
408 } // switch eventName
409
410 if (this.handlers[eventName]) {
411 for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
412 var func = this.handlers[eventName][idx];
413
414 if (typeof(func) == 'function') {
415 // actual function reference
416 func(this, args);
417 }
418 else if ((typeof(func) == 'object') && (func.length == 2)) {
419 // PHP style object + method, i.e. [myObject, 'myMethod']
420 func[0][ func[1] ](this, args);
421 }
422 else if (typeof(func) == 'string') {
423 // name of function
424 window[func](this, args);
425 }
426 } // foreach event handler defined
427 } // user defined handler for event
428 }
429
430 };
431
432 // For the Flash binding to work, ZeroClipboard_TableTools must be on the global
433 // object list
434 window.ZeroClipboard_TableTools = ZeroClipboard_TableTools;
435 //include TableTools.js
436 /* TableTools
437 * 2009-2015 SpryMedia Ltd - datatables.net/license
438 */
439
440 /*globals TableTools,ZeroClipboard_TableTools*/
441
442
443 (function($, window, document) {
444
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 */
460 TableTools = function( oDT, oOpts )
461 {
462 /* Santiy check that we are a new instance */
463 if ( ! this instanceof TableTools )
464 {
465 alert( "Warning: TableTools must be initialised with the keyword 'new'" );
466 }
467
468 // In 1.10 we can use the API to get the settings object from a number of
469 // sources
470 var dtSettings = $.fn.dataTable.Api ?
471 new $.fn.dataTable.Api( oDT ).settings()[0] :
472 oDT.fnSettings();
473
474
475 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
476 * Public class variables
477 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
478
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
750 TableTools.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 inputs
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 work 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 */
2688 TableTools._aInstances = [];
2689
2690
2691 /**
2692 * Store of all listeners and their callback functions
2693 * @property _aListeners
2694 * @type Array
2695 * @default []
2696 */
2697 TableTools._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 */
2711 TableTools.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 */
2730 TableTools.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 */
2758 TableTools._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 */
2780 TableTools._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
2803 TableTools.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 */
2841 TableTools.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
3029 TableTools.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 */
3037 TableTools.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 */
3067 TableTools.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 */
3081 TableTools.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
3104 TableTools.defaults = TableTools.DEFAULTS;
3105
3106
3107 /**
3108 * Name of this class
3109 * @constant CLASS
3110 * @type String
3111 * @default TableTools
3112 */
3113 TableTools.prototype.CLASS = "TableTools";
3114
3115
3116 /**
3117 * TableTools version
3118 * @constant VERSION
3119 * @type String
3120 * @default See code
3121 */
3122 TableTools.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
3132 if ( $.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 */
3154 if ( 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 }
3171 else
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 */
3183 if ( 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 }
3201 else
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
3211 return TableTools;
3212 }; // /factory
3213
3214
3215 // Define as an AMD module if possible
3216 if ( typeof define === 'function' && define.amd ) {
3217 define( ['jquery', 'datatables'], factory );
3218 }
3219 else if ( typeof exports === 'object' ) {
3220 // Node/CommonJS
3221 factory( require('jquery'), require('datatables') );
3222 }
3223 else 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