jquery-datatables-rails 1.10.0 → 1.11.0

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