check into issue that propel doesn't return DateTime object in UTC. using table tools to keep track of selected rows.
2569 lines
65 KiB
JavaScript
Executable file
2569 lines
65 KiB
JavaScript
Executable file
/*
|
|
* File: TableTools.js
|
|
* Version: 2.0.2
|
|
* Description: Tools and buttons for DataTables
|
|
* Author: Allan Jardine (www.sprymedia.co.uk)
|
|
* Language: Javascript
|
|
* License: GPL v2 or BSD 3 point style
|
|
* Project: DataTables
|
|
*
|
|
* Copyright 2009-2012 Allan Jardine, all rights reserved.
|
|
*
|
|
* This source file is free software, under either the GPL v2 license or a
|
|
* BSD style license, available at:
|
|
* http://datatables.net/license_gpl2
|
|
* http://datatables.net/license_bsd
|
|
*/
|
|
|
|
/* Global scope for TableTools */
|
|
var TableTools;
|
|
|
|
(function($, window, document) {
|
|
|
|
/**
|
|
* TableTools provides flexible buttons and other tools for a DataTables enhanced table
|
|
* @class TableTools
|
|
* @constructor
|
|
* @param {Object} oDT DataTables instance
|
|
* @param {Object} oOpts TableTools options
|
|
* @param {String} oOpts.sSwfPath ZeroClipboard SWF path
|
|
* @param {String} oOpts.sRowSelect Row selection options - 'none', 'single' or 'multi'
|
|
* @param {Function} oOpts.fnPreRowSelect Callback function just prior to row selection
|
|
* @param {Function} oOpts.fnRowSelected Callback function just after row selection
|
|
* @param {Function} oOpts.fnRowDeselected Callback function when row is deselected
|
|
* @param {Array} oOpts.aButtons List of buttons to be used
|
|
*/
|
|
TableTools = function( oDT, oOpts )
|
|
{
|
|
/* Santiy check that we are a new instance */
|
|
if ( !this.CLASS || this.CLASS != "TableTools" )
|
|
{
|
|
alert( "Warning: TableTools must be initialised with the keyword 'new'" );
|
|
}
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Public class variables
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/**
|
|
* @namespace Settings object which contains customisable information for TableTools instance
|
|
*/
|
|
this.s = {
|
|
/**
|
|
* Store 'this' so the instance can be retreieved from the settings object
|
|
* @property that
|
|
* @type object
|
|
* @default this
|
|
*/
|
|
"that": this,
|
|
|
|
/**
|
|
* DataTables settings objects
|
|
* @property dt
|
|
* @type object
|
|
* @default null
|
|
*/
|
|
"dt": null,
|
|
|
|
/**
|
|
* @namespace Print specific information
|
|
*/
|
|
"print": {
|
|
/**
|
|
* DataTables draw 'start' point before the printing display was shown
|
|
* @property saveStart
|
|
* @type int
|
|
* @default -1
|
|
*/
|
|
"saveStart": -1,
|
|
|
|
/**
|
|
* DataTables draw 'length' point before the printing display was shown
|
|
* @property saveLength
|
|
* @type int
|
|
* @default -1
|
|
*/
|
|
"saveLength": -1,
|
|
|
|
/**
|
|
* Page scrolling point before the printing display was shown so it can be restored
|
|
* @property saveScroll
|
|
* @type int
|
|
* @default -1
|
|
*/
|
|
"saveScroll": -1,
|
|
|
|
/**
|
|
* Wrapped function to end the print display (to maintain scope)
|
|
* @property funcEnd
|
|
* @type Function
|
|
* @default function () {}
|
|
*/
|
|
"funcEnd": function () {}
|
|
},
|
|
|
|
/**
|
|
* A unique ID is assigned to each button in each instance
|
|
* @property buttonCounter
|
|
* @type int
|
|
* @default 0
|
|
*/
|
|
"buttonCounter": 0,
|
|
|
|
/**
|
|
* @namespace Select rows specific information
|
|
*/
|
|
"select": {
|
|
/**
|
|
* Select type - can be 'none', 'single' or 'multi'
|
|
* @property type
|
|
* @type string
|
|
* @default ""
|
|
*/
|
|
"type": "",
|
|
|
|
/**
|
|
* Array of nodes which are currently selected
|
|
* @property selected
|
|
* @type array
|
|
* @default []
|
|
*/
|
|
"selected": [],
|
|
|
|
/**
|
|
* Function to run before the selection can take place. Will cancel the select if the
|
|
* function returns false
|
|
* @property preRowSelect
|
|
* @type Function
|
|
* @default null
|
|
*/
|
|
"preRowSelect": null,
|
|
|
|
/**
|
|
* Function to run when a row is selected
|
|
* @property postSelected
|
|
* @type Function
|
|
* @default null
|
|
*/
|
|
"postSelected": null,
|
|
|
|
/**
|
|
* Function to run when a row is deselected
|
|
* @property postDeselected
|
|
* @type Function
|
|
* @default null
|
|
*/
|
|
"postDeselected": null,
|
|
|
|
/**
|
|
* Indicate if all rows are selected (needed for server-side processing)
|
|
* @property all
|
|
* @type boolean
|
|
* @default false
|
|
*/
|
|
"all": false,
|
|
|
|
/**
|
|
* Class name to add to selected TR nodes
|
|
* @property selectedClass
|
|
* @type String
|
|
* @default ""
|
|
*/
|
|
"selectedClass": ""
|
|
},
|
|
|
|
/**
|
|
* Store of the user input customisation object
|
|
* @property custom
|
|
* @type object
|
|
* @default {}
|
|
*/
|
|
"custom": {},
|
|
|
|
/**
|
|
* SWF movie path
|
|
* @property swfPath
|
|
* @type string
|
|
* @default ""
|
|
*/
|
|
"swfPath": "",
|
|
|
|
/**
|
|
* Default button set
|
|
* @property buttonSet
|
|
* @type array
|
|
* @default []
|
|
*/
|
|
"buttonSet": [],
|
|
|
|
/**
|
|
* When there is more than one TableTools instance for a DataTable, there must be a
|
|
* master which controls events (row selection etc)
|
|
* @property master
|
|
* @type boolean
|
|
* @default false
|
|
*/
|
|
"master": false
|
|
};
|
|
|
|
|
|
/**
|
|
* @namespace Common and useful DOM elements for the class instance
|
|
*/
|
|
this.dom = {
|
|
/**
|
|
* DIV element that is create and all TableTools buttons (and their children) put into
|
|
* @property container
|
|
* @type node
|
|
* @default null
|
|
*/
|
|
"container": null,
|
|
|
|
/**
|
|
* The table node to which TableTools will be applied
|
|
* @property table
|
|
* @type node
|
|
* @default null
|
|
*/
|
|
"table": null,
|
|
|
|
/**
|
|
* @namespace Nodes used for the print display
|
|
*/
|
|
"print": {
|
|
/**
|
|
* Nodes which have been removed from the display by setting them to display none
|
|
* @property hidden
|
|
* @type array
|
|
* @default []
|
|
*/
|
|
"hidden": [],
|
|
|
|
/**
|
|
* The information display saying tellng the user about the print display
|
|
* @property message
|
|
* @type node
|
|
* @default null
|
|
*/
|
|
"message": null
|
|
},
|
|
|
|
/**
|
|
* @namespace Nodes used for a collection display. This contains the currently used collection
|
|
*/
|
|
"collection": {
|
|
/**
|
|
* The div wrapper containing the buttons in the collection (i.e. the menu)
|
|
* @property collection
|
|
* @type node
|
|
* @default null
|
|
*/
|
|
"collection": null,
|
|
|
|
/**
|
|
* Background display to provide focus and capture events
|
|
* @property background
|
|
* @type node
|
|
* @default null
|
|
*/
|
|
"background": null
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Public class methods
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/**
|
|
* Retreieve the settings object from an instance
|
|
* @method fnSettings
|
|
* @returns {object} TableTools settings object
|
|
*/
|
|
this.fnSettings = function () {
|
|
return this.s;
|
|
};
|
|
|
|
|
|
/* Constructor logic */
|
|
if ( typeof oOpts == 'undefined' )
|
|
{
|
|
oOpts = {};
|
|
}
|
|
|
|
this.s.dt = oDT.fnSettings();
|
|
this._fnConstruct( oOpts );
|
|
|
|
return this;
|
|
};
|
|
|
|
|
|
|
|
TableTools.prototype = {
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Public methods
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/**
|
|
* Retreieve the settings object from an instance
|
|
* @method fnGetSelected
|
|
* @returns {array} List of TR nodes which are currently selected
|
|
*/
|
|
"fnGetSelected": function ()
|
|
{
|
|
var masterS = this._fnGetMasterSettings();
|
|
return masterS.select.selected;
|
|
},
|
|
|
|
|
|
/**
|
|
* Get the data source objects/arrays from DataTables for the selected rows (same as
|
|
* fnGetSelected followed by fnGetData on each row from the table)
|
|
* @method fnGetSelectedData
|
|
* @returns {array} Data from the TR nodes which are currently selected
|
|
*/
|
|
"fnGetSelectedData": function ()
|
|
{
|
|
var masterS = this._fnGetMasterSettings();
|
|
var selected = masterS.select.selected;
|
|
var out = [];
|
|
|
|
for ( var i=0, iLen=selected.length ; i<iLen ; i++ )
|
|
{
|
|
out.push( this.s.dt.oInstance.fnGetData( selected[i] ) );
|
|
}
|
|
|
|
return out;
|
|
},
|
|
|
|
|
|
/**
|
|
* Check to see if a current row is selected or not
|
|
* @method fnGetSelected
|
|
* @param {Node} n TR node to check if it is currently selected or not
|
|
* @returns {Boolean} true if select, false otherwise
|
|
*/
|
|
"fnIsSelected": function ( n )
|
|
{
|
|
var selected = this.fnGetSelected();
|
|
for ( var i=0, iLen=selected.length ; i<iLen ; i++ )
|
|
{
|
|
if ( n == selected[i] )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
|
|
/**
|
|
* Select all rows in the table
|
|
* @method fnSelectAll
|
|
* @returns void
|
|
*/
|
|
"fnSelectAll": function ()
|
|
{
|
|
var masterS = this._fnGetMasterSettings();
|
|
masterS.that._fnRowSelectAll();
|
|
},
|
|
|
|
|
|
/**
|
|
* Deselect all rows in the table
|
|
* @method fnSelectNone
|
|
* @returns void
|
|
*/
|
|
"fnSelectNone": function ()
|
|
{
|
|
var masterS = this._fnGetMasterSettings();
|
|
masterS.that._fnRowDeselectAll();
|
|
},
|
|
|
|
|
|
/**
|
|
* Select an individual row
|
|
* @method fnSelect
|
|
* @returns void
|
|
*/
|
|
"fnSelect": function ( n )
|
|
{
|
|
/* Check if the row is already selected */
|
|
if ( !this.fnIsSelected( n ) )
|
|
{
|
|
if ( this.s.select.type == "single" )
|
|
{
|
|
this._fnRowSelectSingle( n );
|
|
}
|
|
else if ( this.s.select.type == "multi" )
|
|
{
|
|
this._fnRowSelectMulti( n );
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Deselect an individual row
|
|
* @method fnDeselect
|
|
* @returns void
|
|
*/
|
|
"fnDeselect": function ( n )
|
|
{
|
|
/* Check if the row is already deselected */
|
|
if ( this.fnIsSelected( n ) )
|
|
{
|
|
if ( this.s.select.type == "single" )
|
|
{
|
|
this._fnRowSelectSingle( n );
|
|
}
|
|
else if ( this.s.select.type == "multi" )
|
|
{
|
|
this._fnRowSelectMulti( n );
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Get the title of the document - useful for file names. The title is retrieved from either
|
|
* the configuration object's 'title' parameter, or the HTML document title
|
|
* @method fnGetTitle
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns {String} Button title
|
|
*/
|
|
"fnGetTitle": function( oConfig )
|
|
{
|
|
var sTitle = "";
|
|
if ( typeof oConfig.sTitle != 'undefined' && oConfig.sTitle !== "" ) {
|
|
sTitle = oConfig.sTitle;
|
|
} else {
|
|
var anTitle = document.getElementsByTagName('title');
|
|
if ( anTitle.length > 0 )
|
|
{
|
|
sTitle = anTitle[0].innerHTML;
|
|
}
|
|
}
|
|
|
|
/* Strip characters which the OS will object to - checking for UTF8 support in the scripting
|
|
* engine
|
|
*/
|
|
if ( "\u00A1".toString().length < 4 ) {
|
|
return sTitle.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g, "");
|
|
} else {
|
|
return sTitle.replace(/[^a-zA-Z0-9_\.,\-_ !\(\)]/g, "");
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Calculate a unity array with the column width by proportion for a set of columns to be
|
|
* included for a button. This is particularly useful for PDF creation, where we can use the
|
|
* column widths calculated by the browser to size the columns in the PDF.
|
|
* @method fnCalcColRations
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns {Array} Unity array of column ratios
|
|
*/
|
|
"fnCalcColRatios": function ( oConfig )
|
|
{
|
|
var
|
|
aoCols = this.s.dt.aoColumns,
|
|
aColumnsInc = this._fnColumnTargets( oConfig.mColumns ),
|
|
aColWidths = [],
|
|
iWidth = 0, iTotal = 0, i, iLen;
|
|
|
|
for ( i=0, iLen=aColumnsInc.length ; i<iLen ; i++ )
|
|
{
|
|
if ( aColumnsInc[i] )
|
|
{
|
|
iWidth = aoCols[i].nTh.offsetWidth;
|
|
iTotal += iWidth;
|
|
aColWidths.push( iWidth );
|
|
}
|
|
}
|
|
|
|
for ( i=0, iLen=aColWidths.length ; i<iLen ; i++ )
|
|
{
|
|
aColWidths[i] = aColWidths[i] / iTotal;
|
|
}
|
|
|
|
return aColWidths.join('\t');
|
|
},
|
|
|
|
|
|
/**
|
|
* Get the information contained in a table as a string
|
|
* @method fnGetTableData
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns {String} Table data as a string
|
|
*/
|
|
"fnGetTableData": function ( oConfig )
|
|
{
|
|
/* In future this could be used to get data from a plain HTML source as well as DataTables */
|
|
if ( this.s.dt )
|
|
{
|
|
return this._fnGetDataTablesData( oConfig );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Pass text to a flash button instance, which will be used on the button's click handler
|
|
* @method fnSetText
|
|
* @param {Object} clip Flash button object
|
|
* @param {String} text Text to set
|
|
* @returns void
|
|
*/
|
|
"fnSetText": function ( clip, text )
|
|
{
|
|
this._fnFlashSetText( clip, text );
|
|
},
|
|
|
|
|
|
/**
|
|
* Resize the flash elements of the buttons attached to this TableTools instance - this is
|
|
* useful for when initialising TableTools when it is hidden (display:none) since sizes can't
|
|
* be calculated at that time.
|
|
* @method fnResizeButtons
|
|
* @returns void
|
|
*/
|
|
"fnResizeButtons": function ()
|
|
{
|
|
for ( var cli in ZeroClipboard.clients )
|
|
{
|
|
if ( cli )
|
|
{
|
|
var client = ZeroClipboard.clients[cli];
|
|
if ( typeof client.domElement != 'undefined' &&
|
|
client.domElement.parentNode == this.dom.container )
|
|
{
|
|
client.positionElement();
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Check to see if any of the ZeroClipboard client's attached need to be resized
|
|
* @method fnResizeRequired
|
|
* @returns void
|
|
*/
|
|
"fnResizeRequired": function ()
|
|
{
|
|
for ( var cli in ZeroClipboard.clients )
|
|
{
|
|
if ( cli )
|
|
{
|
|
var client = ZeroClipboard.clients[cli];
|
|
if ( typeof client.domElement != 'undefined' &&
|
|
client.domElement.parentNode == this.dom.container &&
|
|
client.sized === false )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Private methods (they are of course public in JS, but recommended as private)
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/**
|
|
* Constructor logic
|
|
* @method _fnConstruct
|
|
* @param {Object} oOpts Same as TableTools constructor
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnConstruct": function ( oOpts )
|
|
{
|
|
var that = this;
|
|
|
|
this._fnCustomiseSettings( oOpts );
|
|
|
|
/* Container element */
|
|
this.dom.container = document.createElement('div');
|
|
this.dom.container.className = !this.s.dt.bJUI ? "DTTT_container" :
|
|
"DTTT_container ui-buttonset ui-buttonset-multi";
|
|
|
|
/* Row selection config */
|
|
if ( this.s.select.type != 'none' )
|
|
{
|
|
this._fnRowSelectConfig();
|
|
}
|
|
|
|
/* Buttons */
|
|
this._fnButtonDefinations( this.s.buttonSet, this.dom.container );
|
|
|
|
/* Destructor - need to wipe the DOM for IE's garbage collector */
|
|
this.s.dt.aoDestroyCallback.push( {
|
|
"sName": "TableTools",
|
|
"fn": function () {
|
|
that.dom.container.innerHTML = "";
|
|
}
|
|
} );
|
|
},
|
|
|
|
|
|
/**
|
|
* Take the user defined settings and the default settings and combine them.
|
|
* @method _fnCustomiseSettings
|
|
* @param {Object} oOpts Same as TableTools constructor
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnCustomiseSettings": function ( oOpts )
|
|
{
|
|
/* Is this the master control instance or not? */
|
|
if ( typeof this.s.dt._TableToolsInit == 'undefined' )
|
|
{
|
|
this.s.master = true;
|
|
this.s.dt._TableToolsInit = true;
|
|
}
|
|
|
|
/* We can use the table node from comparisons to group controls */
|
|
this.dom.table = this.s.dt.nTable;
|
|
|
|
/* Clone the defaults and then the user options */
|
|
this.s.custom = $.extend( {}, TableTools.DEFAULTS, oOpts );
|
|
|
|
/* Flash file location */
|
|
this.s.swfPath = this.s.custom.sSwfPath;
|
|
if ( typeof ZeroClipboard != 'undefined' )
|
|
{
|
|
ZeroClipboard.moviePath = this.s.swfPath;
|
|
}
|
|
|
|
/* Table row selecting */
|
|
this.s.select.type = this.s.custom.sRowSelect;
|
|
this.s.select.preRowSelect = this.s.custom.fnPreRowSelect;
|
|
this.s.select.postSelected = this.s.custom.fnRowSelected;
|
|
this.s.select.postDeselected = this.s.custom.fnRowDeselected;
|
|
this.s.select.selectedClass = this.s.custom.sSelectedClass;
|
|
|
|
/* Button set */
|
|
this.s.buttonSet = this.s.custom.aButtons;
|
|
},
|
|
|
|
|
|
/**
|
|
* Take the user input arrays and expand them to be fully defined, and then add them to a given
|
|
* DOM element
|
|
* @method _fnButtonDefinations
|
|
* @param {array} buttonSet Set of user defined buttons
|
|
* @param {node} wrapper Node to add the created buttons to
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnButtonDefinations": function ( buttonSet, wrapper )
|
|
{
|
|
var buttonDef;
|
|
|
|
for ( var i=0, iLen=buttonSet.length ; i<iLen ; i++ )
|
|
{
|
|
if ( typeof buttonSet[i] == "string" )
|
|
{
|
|
if ( typeof TableTools.BUTTONS[ buttonSet[i] ] == 'undefined' )
|
|
{
|
|
alert( "TableTools: Warning - unknown button type: "+buttonSet[i] );
|
|
continue;
|
|
}
|
|
buttonDef = $.extend( {}, TableTools.BUTTONS[ buttonSet[i] ], true );
|
|
}
|
|
else
|
|
{
|
|
if ( typeof TableTools.BUTTONS[ buttonSet[i].sExtends ] == 'undefined' )
|
|
{
|
|
alert( "TableTools: Warning - unknown button type: "+buttonSet[i].sExtends );
|
|
continue;
|
|
}
|
|
var o = $.extend( {}, TableTools.BUTTONS[ buttonSet[i].sExtends ], true );
|
|
buttonDef = $.extend( o, buttonSet[i], true );
|
|
}
|
|
|
|
if ( this.s.dt.bJUI )
|
|
{
|
|
buttonDef.sButtonClass += " ui-button ui-state-default";
|
|
buttonDef.sButtonClassHover += " ui-state-hover";
|
|
}
|
|
|
|
wrapper.appendChild( this._fnCreateButton( buttonDef ) );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Create and configure a TableTools button
|
|
* @method _fnCreateButton
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns {Node} Button element
|
|
* @private
|
|
*/
|
|
"_fnCreateButton": function ( oConfig )
|
|
{
|
|
var nButton = (oConfig.sAction == 'div') ?
|
|
this._fnDivBase( oConfig ) : this._fnButtonBase( oConfig );
|
|
|
|
if ( oConfig.sAction == "print" )
|
|
{
|
|
this._fnPrintConfig( nButton, oConfig );
|
|
}
|
|
else if ( oConfig.sAction.match(/flash/) )
|
|
{
|
|
this._fnFlashConfig( nButton, oConfig );
|
|
}
|
|
else if ( oConfig.sAction == "text" )
|
|
{
|
|
this._fnTextConfig( nButton, oConfig );
|
|
}
|
|
else if ( oConfig.sAction == "div" )
|
|
{
|
|
this._fnTextConfig( nButton, oConfig );
|
|
}
|
|
else if ( oConfig.sAction == "collection" )
|
|
{
|
|
this._fnTextConfig( nButton, oConfig );
|
|
this._fnCollectionConfig( nButton, oConfig );
|
|
}
|
|
|
|
return nButton;
|
|
},
|
|
|
|
|
|
/**
|
|
* Create the DOM needed for the button and apply some base properties. All buttons start here
|
|
* @method _fnButtonBase
|
|
* @param {o} oConfig Button configuration object
|
|
* @returns {Node} DIV element for the button
|
|
* @private
|
|
*/
|
|
"_fnButtonBase": function ( o )
|
|
{
|
|
var
|
|
nButton = document.createElement('button'),
|
|
nSpan = document.createElement('span'),
|
|
masterS = this._fnGetMasterSettings();
|
|
|
|
nButton.className = "DTTT_button "+o.sButtonClass;
|
|
nButton.setAttribute('id', "ToolTables_"+this.s.dt.sInstance+"_"+masterS.buttonCounter );
|
|
nButton.appendChild( nSpan );
|
|
nSpan.innerHTML = o.sButtonText;
|
|
|
|
masterS.buttonCounter++;
|
|
|
|
return nButton;
|
|
},
|
|
|
|
|
|
/**
|
|
* Create a DIV element to use for a non-button
|
|
* @method _fnDivBase
|
|
* @param {o} oConfig Button configuration object
|
|
* @returns {Node} DIV element for the button
|
|
* @private
|
|
*/
|
|
"_fnDivBase": function ( o )
|
|
{
|
|
var
|
|
nDiv = document.createElement('div'),
|
|
masterS = this._fnGetMasterSettings();
|
|
|
|
nDiv.className = o.sButtonClass;
|
|
nDiv.setAttribute('id', "ToolTables_"+this.s.dt.sInstance+"_"+masterS.buttonCounter );
|
|
nDiv.innerHTML = o.sButtonText;
|
|
|
|
if ( o.nContent !== null )
|
|
{
|
|
nDiv.appendChild( o.nContent );
|
|
}
|
|
|
|
masterS.buttonCounter++;
|
|
|
|
return nDiv;
|
|
},
|
|
|
|
|
|
/**
|
|
* Get the settings object for the master instance. When more than one TableTools instance is
|
|
* assigned to a DataTable, only one of them can be the 'master' (for the select rows). As such,
|
|
* we will typically want to interact with that master for global properties.
|
|
* @method _fnGetMasterSettings
|
|
* @returns {Object} TableTools settings object
|
|
* @private
|
|
*/
|
|
"_fnGetMasterSettings": function ()
|
|
{
|
|
if ( this.s.master )
|
|
{
|
|
return this.s;
|
|
}
|
|
else
|
|
{
|
|
/* Look for the master which has the same DT as this one */
|
|
var instances = TableTools._aInstances;
|
|
for ( var i=0, iLen=instances.length ; i<iLen ; i++ )
|
|
{
|
|
if ( this.dom.table == instances[i].s.dt.nTable )
|
|
{
|
|
return instances[i].s;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Button collection functions
|
|
*/
|
|
|
|
/**
|
|
* Create a collection button, when activated will present a drop downlist of other buttons
|
|
* @param {Node} nButton Button to use for the collection activation
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnCollectionConfig": function ( nButton, oConfig )
|
|
{
|
|
var nHidden = document.createElement('div');
|
|
nHidden.style.display = "none";
|
|
nHidden.className = !this.s.dt.bJUI ? "DTTT_collection" :
|
|
"DTTT_collection ui-buttonset ui-buttonset-multi";
|
|
oConfig._collection = nHidden;
|
|
|
|
this._fnButtonDefinations( oConfig.aButtons, nHidden );
|
|
},
|
|
|
|
|
|
/**
|
|
* Show a button collection
|
|
* @param {Node} nButton Button to use for the collection
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnCollectionShow": function ( nButton, oConfig )
|
|
{
|
|
var
|
|
that = this,
|
|
oPos = $(nButton).offset(),
|
|
nHidden = oConfig._collection,
|
|
iDivX = oPos.left,
|
|
iDivY = oPos.top + $(nButton).outerHeight(),
|
|
iWinHeight = $(window).height(), iDocHeight = $(document).height(),
|
|
iWinWidth = $(window).width(), iDocWidth = $(document).width();
|
|
|
|
nHidden.style.position = "absolute";
|
|
nHidden.style.left = iDivX+"px";
|
|
nHidden.style.top = iDivY+"px";
|
|
nHidden.style.display = "block";
|
|
$(nHidden).css('opacity',0);
|
|
|
|
var nBackground = document.createElement('div');
|
|
nBackground.style.position = "absolute";
|
|
nBackground.style.left = "0px";
|
|
nBackground.style.top = "0px";
|
|
nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px";
|
|
nBackground.style.width = ((iWinWidth>iDocWidth)? iWinWidth : iDocWidth) +"px";
|
|
nBackground.className = "DTTT_collection_background";
|
|
$(nBackground).css('opacity',0);
|
|
|
|
document.body.appendChild( nBackground );
|
|
document.body.appendChild( nHidden );
|
|
|
|
/* Visual corrections to try and keep the collection visible */
|
|
var iDivWidth = $(nHidden).outerWidth();
|
|
var iDivHeight = $(nHidden).outerHeight();
|
|
|
|
if ( iDivX + iDivWidth > iDocWidth )
|
|
{
|
|
nHidden.style.left = (iDocWidth-iDivWidth)+"px";
|
|
}
|
|
|
|
if ( iDivY + iDivHeight > iDocHeight )
|
|
{
|
|
nHidden.style.top = (iDivY-iDivHeight-$(nButton).outerHeight())+"px";
|
|
}
|
|
|
|
this.dom.collection.collection = nHidden;
|
|
this.dom.collection.background = nBackground;
|
|
|
|
/* This results in a very small delay for the end user but it allows the animation to be
|
|
* much smoother. If you don't want the animation, then the setTimeout can be removed
|
|
*/
|
|
setTimeout( function () {
|
|
$(nHidden).animate({"opacity": 1}, 500);
|
|
$(nBackground).animate({"opacity": 0.25}, 500);
|
|
}, 10 );
|
|
|
|
/* Event handler to remove the collection display */
|
|
$(nBackground).click( function () {
|
|
that._fnCollectionHide.call( that, null, null );
|
|
} );
|
|
},
|
|
|
|
|
|
/**
|
|
* Hide a button collection
|
|
* @param {Node} nButton Button to use for the collection
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnCollectionHide": function ( nButton, oConfig )
|
|
{
|
|
if ( oConfig !== null && oConfig.sExtends == 'collection' )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( this.dom.collection.collection !== null )
|
|
{
|
|
$(this.dom.collection.collection).animate({"opacity": 0}, 500, function (e) {
|
|
this.style.display = "none";
|
|
} );
|
|
|
|
$(this.dom.collection.background).animate({"opacity": 0}, 500, function (e) {
|
|
this.parentNode.removeChild( this );
|
|
} );
|
|
|
|
this.dom.collection.collection = null;
|
|
this.dom.collection.background = null;
|
|
}
|
|
},
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Row selection functions
|
|
*/
|
|
|
|
/**
|
|
* Add event handlers to a table to allow for row selection
|
|
* @method _fnRowSelectConfig
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnRowSelectConfig": function ()
|
|
{
|
|
if ( this.s.master )
|
|
{
|
|
var
|
|
that = this,
|
|
i, iLen,
|
|
aoOpenRows = this.s.dt.aoOpenRows;
|
|
|
|
$(that.s.dt.nTable).addClass( 'DTTT_selectable' );
|
|
|
|
$('tr', that.s.dt.nTBody).live( 'click', function(e) {
|
|
/* Sub-table must be ignored (odd that the selector won't do this with >) */
|
|
if ( this.parentNode != that.s.dt.nTBody )
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* Check that we are actually working with a DataTables controlled row */
|
|
var anTableRows = that.s.dt.oInstance.fnGetNodes();
|
|
if ( $.inArray( this, anTableRows ) === -1 ) {
|
|
return;
|
|
}
|
|
|
|
/* User defined selection function */
|
|
if ( that.s.select.preRowSelect !== null && !that.s.select.preRowSelect.call(that, e) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* And go */
|
|
if ( that.s.select.type == "single" )
|
|
{
|
|
that._fnRowSelectSingle.call( that, this );
|
|
}
|
|
else
|
|
{
|
|
that._fnRowSelectMulti.call( that, this );
|
|
}
|
|
} );
|
|
|
|
/* Add a draw callback handler for when 'select' all is active and we are using server-side
|
|
* processing, so TableTools will automatically select the new rows for us
|
|
*/
|
|
that.s.dt.aoDrawCallback.push( {
|
|
"fn": function () {
|
|
if ( that.s.select.all && that.s.dt.oFeatures.bServerSide )
|
|
{
|
|
that.fnSelectAll();
|
|
}
|
|
},
|
|
"sName": "TableTools_select"
|
|
} );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Select or deselect a row based on its current state when only one row is allowed to be
|
|
* selected at a time (i.e. if there is a row already selected, deselect it). If the selected
|
|
* row is the one being passed in, just deselect and take no further action.
|
|
* @method _fnRowSelectSingle
|
|
* @param {Node} nNode TR element which is being 'activated' in some way
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnRowSelectSingle": function ( nNode )
|
|
{
|
|
if ( this.s.master )
|
|
{
|
|
/* Do nothing on the DataTables 'empty' result set row */
|
|
if ( $('td', nNode).hasClass(this.s.dt.oClasses.sRowEmpty) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( $(nNode).hasClass(this.s.select.selectedClass) )
|
|
{
|
|
this._fnRowDeselect( nNode );
|
|
}
|
|
else
|
|
{
|
|
if ( this.s.select.selected.length !== 0 )
|
|
{
|
|
this._fnRowDeselectAll();
|
|
}
|
|
|
|
this.s.select.selected.push( nNode );
|
|
$(nNode).addClass( this.s.select.selectedClass );
|
|
|
|
if ( this.s.select.postSelected !== null )
|
|
{
|
|
this.s.select.postSelected.call( this, nNode );
|
|
}
|
|
}
|
|
|
|
TableTools._fnEventDispatch( this, 'select', nNode );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Select or deselect a row based on its current state when multiple rows are allowed to be
|
|
* selected.
|
|
* @method _fnRowSelectMulti
|
|
* @param {Node} nNode TR element which is being 'activated' in some way
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnRowSelectMulti": function ( nNode )
|
|
{
|
|
if ( this.s.master )
|
|
{
|
|
/* Do nothing on the DataTables 'empty' result set row */
|
|
if ( $('td', nNode).hasClass(this.s.dt.oClasses.sRowEmpty) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( $(nNode).hasClass(this.s.select.selectedClass) )
|
|
{
|
|
this._fnRowDeselect( nNode );
|
|
}
|
|
else
|
|
{
|
|
this.s.select.selected.push( nNode );
|
|
$(nNode).addClass( this.s.select.selectedClass );
|
|
|
|
if ( this.s.select.postSelected !== null )
|
|
{
|
|
this.s.select.postSelected.call( this, nNode );
|
|
}
|
|
}
|
|
|
|
TableTools._fnEventDispatch( this, 'select', nNode );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Select all TR elements in the table. Note that this function will still operate in 'single'
|
|
* select mode, which might not be what you desire (in which case, don't call this function!)
|
|
* @method _fnRowSelectAll
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnRowSelectAll": function ( )
|
|
{
|
|
if ( this.s.master )
|
|
{
|
|
var n;
|
|
for ( var i=0, iLen=this.s.dt.aiDisplayMaster.length ; i<iLen ; i++ )
|
|
{
|
|
n = this.s.dt.aoData[ this.s.dt.aiDisplayMaster[i] ].nTr;
|
|
|
|
if ( !$(n).hasClass(this.s.select.selectedClass) )
|
|
{
|
|
this.s.select.selected.push( n );
|
|
$(n).addClass( this.s.select.selectedClass );
|
|
}
|
|
}
|
|
|
|
if ( this.s.select.postSelected !== null )
|
|
{
|
|
this.s.select.postSelected.call( this, null );
|
|
}
|
|
|
|
this.s.select.all = true;
|
|
TableTools._fnEventDispatch( this, 'select', null );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Deselect all TR elements in the table. If nothing is currently selected, then no action is
|
|
* taken.
|
|
* @method _fnRowDeselectAll
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnRowDeselectAll": function ( )
|
|
{
|
|
if ( this.s.master )
|
|
{
|
|
for ( var i=this.s.select.selected.length-1 ; i>=0 ; i-- )
|
|
{
|
|
this._fnRowDeselect( i, false );
|
|
}
|
|
|
|
if ( this.s.select.postDeselected !== null )
|
|
{
|
|
this.s.select.postDeselected.call( this, null );
|
|
}
|
|
|
|
this.s.select.all = false;
|
|
TableTools._fnEventDispatch( this, 'select', null );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Deselect a single row, based on its index in the selected array, or a TR node (when the
|
|
* index is then computed)
|
|
* @method _fnRowDeselect
|
|
* @param {int|Node} i Node or index of node in selected array, which is to be deselected
|
|
* @param {bool} [action=true] Run the post deselected method or not
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnRowDeselect": function ( i, action )
|
|
{
|
|
if ( typeof i.nodeName != 'undefined' )
|
|
{
|
|
i = $.inArray( i, this.s.select.selected );
|
|
}
|
|
|
|
var nNode = this.s.select.selected[i];
|
|
$(nNode).removeClass(this.s.select.selectedClass);
|
|
this.s.select.selected.splice( i, 1 );
|
|
|
|
if ( (typeof action == 'undefined' || action) && this.s.select.postDeselected !== null )
|
|
{
|
|
this.s.select.postDeselected.call( this, nNode );
|
|
}
|
|
|
|
this.s.select.all = false;
|
|
},
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Text button functions
|
|
*/
|
|
|
|
/**
|
|
* Configure a text based button for interaction events
|
|
* @method _fnTextConfig
|
|
* @param {Node} nButton Button element which is being considered
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnTextConfig": function ( nButton, oConfig )
|
|
{
|
|
var that = this;
|
|
|
|
if ( oConfig.fnInit !== null )
|
|
{
|
|
oConfig.fnInit.call( this, nButton, oConfig );
|
|
}
|
|
|
|
if ( oConfig.sToolTip !== "" )
|
|
{
|
|
nButton.title = oConfig.sToolTip;
|
|
}
|
|
|
|
$(nButton).hover( function () {
|
|
$(nButton).addClass(oConfig.sButtonClassHover );
|
|
if ( oConfig.fnMouseover !== null )
|
|
{
|
|
oConfig.fnMouseover.call( this, nButton, oConfig, null );
|
|
}
|
|
}, function () {
|
|
$(nButton).removeClass( oConfig.sButtonClassHover );
|
|
if ( oConfig.fnMouseout !== null )
|
|
{
|
|
oConfig.fnMouseout.call( this, nButton, oConfig, null );
|
|
}
|
|
} );
|
|
|
|
if ( oConfig.fnSelect !== null )
|
|
{
|
|
TableTools._fnEventListen( this, 'select', function (n) {
|
|
oConfig.fnSelect.call( that, nButton, oConfig, n );
|
|
} );
|
|
}
|
|
|
|
$(nButton).click( function (e) {
|
|
e.preventDefault();
|
|
|
|
if ( oConfig.fnClick !== null )
|
|
{
|
|
oConfig.fnClick.call( that, nButton, oConfig, null );
|
|
}
|
|
|
|
/* Provide a complete function to match the behaviour of the flash elements */
|
|
if ( oConfig.fnComplete !== null )
|
|
{
|
|
oConfig.fnComplete.call( that, nButton, oConfig, null, null );
|
|
}
|
|
|
|
that._fnCollectionHide( nButton, oConfig );
|
|
} );
|
|
},
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Flash button functions
|
|
*/
|
|
|
|
/**
|
|
* Configure a flash based button for interaction events
|
|
* @method _fnFlashConfig
|
|
* @param {Node} nButton Button element which is being considered
|
|
* @param {o} oConfig Button configuration object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnFlashConfig": function ( nButton, oConfig )
|
|
{
|
|
var that = this;
|
|
var flash = new ZeroClipboard.Client();
|
|
|
|
if ( oConfig.fnInit !== null )
|
|
{
|
|
oConfig.fnInit.call( this, nButton, oConfig );
|
|
}
|
|
|
|
flash.setHandCursor( true );
|
|
|
|
if ( oConfig.sAction == "flash_save" )
|
|
{
|
|
flash.setAction( 'save' );
|
|
flash.setCharSet( (oConfig.sCharSet=="utf16le") ? 'UTF16LE' : 'UTF8' );
|
|
flash.setBomInc( oConfig.bBomInc );
|
|
flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) );
|
|
}
|
|
else if ( oConfig.sAction == "flash_pdf" )
|
|
{
|
|
flash.setAction( 'pdf' );
|
|
flash.setFileName( oConfig.sFileName.replace('*', this.fnGetTitle(oConfig)) );
|
|
}
|
|
else
|
|
{
|
|
flash.setAction( 'copy' );
|
|
}
|
|
|
|
flash.addEventListener('mouseOver', function(client) {
|
|
$(nButton).addClass(oConfig.sButtonClassHover );
|
|
|
|
if ( oConfig.fnMouseover !== null )
|
|
{
|
|
oConfig.fnMouseover.call( that, nButton, oConfig, flash );
|
|
}
|
|
} );
|
|
|
|
flash.addEventListener('mouseOut', function(client) {
|
|
$(nButton).removeClass( oConfig.sButtonClassHover );
|
|
|
|
if ( oConfig.fnMouseout !== null )
|
|
{
|
|
oConfig.fnMouseout.call( that, nButton, oConfig, flash );
|
|
}
|
|
} );
|
|
|
|
flash.addEventListener('mouseDown', function(client) {
|
|
if ( oConfig.fnClick !== null )
|
|
{
|
|
oConfig.fnClick.call( that, nButton, oConfig, flash );
|
|
}
|
|
} );
|
|
|
|
flash.addEventListener('complete', function (client, text) {
|
|
if ( oConfig.fnComplete !== null )
|
|
{
|
|
oConfig.fnComplete.call( that, nButton, oConfig, flash, text );
|
|
}
|
|
that._fnCollectionHide( nButton, oConfig );
|
|
} );
|
|
|
|
this._fnFlashGlue( flash, nButton, oConfig.sToolTip );
|
|
},
|
|
|
|
|
|
/**
|
|
* Wait until the id is in the DOM before we "glue" the swf. Note that this function will call
|
|
* itself (using setTimeout) until it completes successfully
|
|
* @method _fnFlashGlue
|
|
* @param {Object} clip Zero clipboard object
|
|
* @param {Node} node node to glue swf to
|
|
* @param {String} text title of the flash movie
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnFlashGlue": function ( flash, node, text )
|
|
{
|
|
var that = this;
|
|
var id = node.getAttribute('id');
|
|
|
|
if ( document.getElementById(id) )
|
|
{
|
|
flash.glue( node, text );
|
|
|
|
/* Catch those who are using a TableTools 1 version of ZeroClipboard */
|
|
if ( flash.domElement.parentNode != flash.div.parentNode &&
|
|
typeof that.__bZCWarning == 'undefined' )
|
|
{
|
|
that.s.dt.oApi._fnLog( this.s.dt, 0, "It looks like you are using the version of "+
|
|
"ZeroClipboard which came with TableTools 1. Please update to use the version that "+
|
|
"came with TableTools 2." );
|
|
that.__bZCWarning = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setTimeout( function () {
|
|
that._fnFlashGlue( flash, node, text );
|
|
}, 100 );
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Set the text for the flash clip to deal with
|
|
*
|
|
* This function is required for large information sets. There is a limit on the
|
|
* amount of data that can be transfered between Javascript and Flash in a single call, so
|
|
* we use this method to build up the text in Flash by sending over chunks. It is estimated
|
|
* that the data limit is around 64k, although it is undocuments, and appears to be different
|
|
* between different flash versions. We chunk at 8KiB.
|
|
* @method _fnFlashSetText
|
|
* @param {Object} clip the ZeroClipboard object
|
|
* @param {String} sData the data to be set
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnFlashSetText": function ( clip, sData )
|
|
{
|
|
var asData = this._fnChunkData( sData, 8192 );
|
|
|
|
clip.clearText();
|
|
for ( var i=0, iLen=asData.length ; i<iLen ; i++ )
|
|
{
|
|
clip.appendText( asData[i] );
|
|
}
|
|
},
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Data retrieval functions
|
|
*/
|
|
|
|
/**
|
|
* Convert the mixed columns variable into a boolean array the same size as the columns, which
|
|
* indicates which columns we want to include
|
|
* @method _fnColumnTargets
|
|
* @param {String|Array} mColumns The columns to be included in data retreieval. If a string
|
|
* then it can take the value of "visible" or "hidden" (to include all visible or
|
|
* hidden columns respectively). Or an array of column indexes
|
|
* @returns {Array} A boolean array the length of the columns of the table, which each value
|
|
* indicating if the column is to be included or not
|
|
* @private
|
|
*/
|
|
"_fnColumnTargets": function ( mColumns )
|
|
{
|
|
var aColumns = [];
|
|
var dt = this.s.dt;
|
|
|
|
if ( typeof mColumns == "object" )
|
|
{
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
aColumns.push( false );
|
|
}
|
|
|
|
for ( i=0, iLen=mColumns.length ; i<iLen ; i++ )
|
|
{
|
|
aColumns[ mColumns[i] ] = true;
|
|
}
|
|
}
|
|
else if ( mColumns == "visible" )
|
|
{
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
aColumns.push( dt.aoColumns[i].bVisible ? true : false );
|
|
}
|
|
}
|
|
else if ( mColumns == "hidden" )
|
|
{
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
aColumns.push( dt.aoColumns[i].bVisible ? false : true );
|
|
}
|
|
}
|
|
else if ( mColumns == "sortable" )
|
|
{
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
aColumns.push( dt.aoColumns[i].bSortable ? true : false );
|
|
}
|
|
}
|
|
else /* all */
|
|
{
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
aColumns.push( true );
|
|
}
|
|
}
|
|
|
|
return aColumns;
|
|
},
|
|
|
|
|
|
/**
|
|
* New line character(s) depend on the platforms
|
|
* @method method
|
|
* @param {Object} oConfig Button configuration object - only interested in oConfig.sNewLine
|
|
* @returns {String} Newline character
|
|
*/
|
|
"_fnNewline": function ( oConfig )
|
|
{
|
|
if ( oConfig.sNewLine == "auto" )
|
|
{
|
|
return navigator.userAgent.match(/Windows/) ? "\r\n" : "\n";
|
|
}
|
|
else
|
|
{
|
|
return oConfig.sNewLine;
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Get data from DataTables' internals and format it for output
|
|
* @method _fnGetDataTablesData
|
|
* @param {Object} oConfig Button configuration object
|
|
* @param {String} oConfig.sFieldBoundary Field boundary for the data cells in the string
|
|
* @param {String} oConfig.sFieldSeperator Field seperator for the data cells
|
|
* @param {String} oConfig.sNewline New line options
|
|
* @param {Mixed} oConfig.mColumns Which columns should be included in the output
|
|
* @param {Boolean} oConfig.bHeader Include the header
|
|
* @param {Boolean} oConfig.bFooter Include the footer
|
|
* @param {Boolean} oConfig.bSelectedOnly Include only the selected rows in the output
|
|
* @returns {String} Concatinated string of data
|
|
* @private
|
|
*/
|
|
"_fnGetDataTablesData": function ( oConfig )
|
|
{
|
|
var i, iLen, j, jLen;
|
|
var sData = '', sLoopData = '';
|
|
var dt = this.s.dt;
|
|
var regex = new RegExp(oConfig.sFieldBoundary, "g"); /* Do it here for speed */
|
|
var aColumnsInc = this._fnColumnTargets( oConfig.mColumns );
|
|
var sNewline = this._fnNewline( oConfig );
|
|
var bSelectedOnly = (typeof oConfig.bSelectedOnly != 'undefined') ? oConfig.bSelectedOnly : false;
|
|
|
|
/*
|
|
* Header
|
|
*/
|
|
if ( oConfig.bHeader )
|
|
{
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
if ( aColumnsInc[i] )
|
|
{
|
|
sLoopData = dt.aoColumns[i].sTitle.replace(/\n/g," ").replace( /<.*?>/g, "" ).replace(/^\s+|\s+$/g,"");
|
|
sLoopData = this._fnHtmlDecode( sLoopData );
|
|
|
|
sData += this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) +
|
|
oConfig.sFieldSeperator;
|
|
}
|
|
}
|
|
sData = sData.slice( 0, oConfig.sFieldSeperator.length*-1 );
|
|
sData += sNewline;
|
|
}
|
|
|
|
/*
|
|
* Body
|
|
*/
|
|
for ( j=0, jLen=dt.aiDisplay.length ; j<jLen ; j++ )
|
|
{
|
|
if ( this.s.select.type == "none" ||
|
|
(bSelectedOnly && $(dt.aoData[ dt.aiDisplay[j] ].nTr).hasClass( this.s.select.selectedClass )) ||
|
|
(bSelectedOnly && this.s.select.selected.length == 0) )
|
|
{
|
|
/* Columns */
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
if ( aColumnsInc[i] )
|
|
{
|
|
/* Convert to strings (with small optimisation) */
|
|
var mTypeData = dt.oApi._fnGetCellData( dt, dt.aiDisplay[j], i, 'display' );
|
|
if ( oConfig.fnCellRender )
|
|
{
|
|
sLoopData = oConfig.fnCellRender( mTypeData, i )+"";
|
|
}
|
|
else if ( typeof mTypeData == "string" )
|
|
{
|
|
/* Strip newlines, replace img tags with alt attr. and finally strip html... */
|
|
sLoopData = mTypeData.replace(/\n/g," ");
|
|
sLoopData =
|
|
sLoopData.replace(/<img.*?\s+alt\s*=\s*(?:"([^"]+)"|'([^']+)'|([^\s>]+)).*?>/gi,
|
|
'$1$2$3');
|
|
sLoopData = sLoopData.replace( /<.*?>/g, "" );
|
|
}
|
|
else
|
|
{
|
|
sLoopData = mTypeData+"";
|
|
}
|
|
|
|
/* Trim and clean the data */
|
|
sLoopData = sLoopData.replace(/^\s+/, '').replace(/\s+$/, '');
|
|
sLoopData = this._fnHtmlDecode( sLoopData );
|
|
|
|
/* Bound it and add it to the total data */
|
|
sData += this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) +
|
|
oConfig.sFieldSeperator;
|
|
}
|
|
}
|
|
sData = sData.slice( 0, oConfig.sFieldSeperator.length*-1 );
|
|
sData += sNewline;
|
|
}
|
|
}
|
|
|
|
/* Remove the last new line */
|
|
sData.slice( 0, -1 );
|
|
|
|
/*
|
|
* Footer
|
|
*/
|
|
if ( oConfig.bFooter )
|
|
{
|
|
for ( i=0, iLen=dt.aoColumns.length ; i<iLen ; i++ )
|
|
{
|
|
if ( aColumnsInc[i] && dt.aoColumns[i].nTf !== null )
|
|
{
|
|
sLoopData = dt.aoColumns[i].nTf.innerHTML.replace(/\n/g," ").replace( /<.*?>/g, "" );
|
|
sLoopData = this._fnHtmlDecode( sLoopData );
|
|
|
|
sData += this._fnBoundData( sLoopData, oConfig.sFieldBoundary, regex ) +
|
|
oConfig.sFieldSeperator;
|
|
}
|
|
}
|
|
sData = sData.slice( 0, oConfig.sFieldSeperator.length*-1 );
|
|
}
|
|
|
|
/* No pointers here - this is a string copy :-) */
|
|
_sLastData = sData;
|
|
return sData;
|
|
},
|
|
|
|
|
|
/**
|
|
* Wrap data up with a boundary string
|
|
* @method _fnBoundData
|
|
* @param {String} sData data to bound
|
|
* @param {String} sBoundary bounding char(s)
|
|
* @param {RegExp} regex search for the bounding chars - constructed outside for efficincy
|
|
* in the loop
|
|
* @returns {String} bound data
|
|
* @private
|
|
*/
|
|
"_fnBoundData": function ( sData, sBoundary, regex )
|
|
{
|
|
if ( sBoundary === "" )
|
|
{
|
|
return sData;
|
|
}
|
|
else
|
|
{
|
|
return sBoundary + sData.replace(regex, sBoundary+sBoundary) + sBoundary;
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Break a string up into an array of smaller strings
|
|
* @method _fnChunkData
|
|
* @param {String} sData data to be broken up
|
|
* @param {Int} iSize chunk size
|
|
* @returns {Array} String array of broken up text
|
|
* @private
|
|
*/
|
|
"_fnChunkData": function ( sData, iSize )
|
|
{
|
|
var asReturn = [];
|
|
var iStrlen = sData.length;
|
|
|
|
for ( var i=0 ; i<iStrlen ; i+=iSize )
|
|
{
|
|
if ( i+iSize < iStrlen )
|
|
{
|
|
asReturn.push( sData.substring( i, i+iSize ) );
|
|
}
|
|
else
|
|
{
|
|
asReturn.push( sData.substring( i, iStrlen ) );
|
|
}
|
|
}
|
|
|
|
return asReturn;
|
|
},
|
|
|
|
|
|
/**
|
|
* Decode HTML entities
|
|
* @method _fnHtmlDecode
|
|
* @param {String} sData encoded string
|
|
* @returns {String} decoded string
|
|
* @private
|
|
*/
|
|
"_fnHtmlDecode": function ( sData )
|
|
{
|
|
if ( sData.indexOf('&') == -1 )
|
|
{
|
|
return sData;
|
|
}
|
|
|
|
var
|
|
aData = this._fnChunkData( sData, 2048 ),
|
|
n = document.createElement('div'),
|
|
i, iLen, iIndex,
|
|
sReturn = "", sInner;
|
|
|
|
/* nodeValue has a limit in browsers - so we chunk the data into smaller segments to build
|
|
* up the string. Note that the 'trick' here is to remember than we might have split over
|
|
* an HTML entity, so we backtrack a little to make sure this doesn't happen
|
|
*/
|
|
for ( i=0, iLen=aData.length ; i<iLen ; i++ )
|
|
{
|
|
/* Magic number 8 is because no entity is longer then strlen 8 in ISO 8859-1 */
|
|
iIndex = aData[i].lastIndexOf( '&' );
|
|
if ( iIndex != -1 && aData[i].length >= 8 && iIndex > aData[i].length - 8 )
|
|
{
|
|
sInner = aData[i].substr( iIndex );
|
|
aData[i] = aData[i].substr( 0, iIndex );
|
|
}
|
|
|
|
n.innerHTML = aData[i];
|
|
sReturn += n.childNodes[0].nodeValue;
|
|
}
|
|
|
|
return sReturn;
|
|
},
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Printing functions
|
|
*/
|
|
|
|
/**
|
|
* Configure a button for printing
|
|
* @method _fnPrintConfig
|
|
* @param {Node} nButton Button element which is being considered
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnPrintConfig": function ( nButton, oConfig )
|
|
{
|
|
var that = this;
|
|
|
|
if ( oConfig.fnInit !== null )
|
|
{
|
|
oConfig.fnInit.call( this, nButton, oConfig );
|
|
}
|
|
|
|
if ( oConfig.sToolTip !== "" )
|
|
{
|
|
nButton.title = oConfig.sToolTip;
|
|
}
|
|
|
|
$(nButton).hover( function () {
|
|
$(nButton).addClass(oConfig.sButtonClassHover );
|
|
}, function () {
|
|
$(nButton).removeClass( oConfig.sButtonClassHover );
|
|
} );
|
|
|
|
if ( oConfig.fnSelect !== null )
|
|
{
|
|
TableTools._fnEventListen( this, 'select', function (n) {
|
|
oConfig.fnSelect.call( that, nButton, oConfig, n );
|
|
} );
|
|
}
|
|
|
|
$(nButton).click( function (e) {
|
|
e.preventDefault();
|
|
|
|
that._fnPrintStart.call( that, e, oConfig);
|
|
|
|
if ( oConfig.fnClick !== null )
|
|
{
|
|
oConfig.fnClick.call( that, nButton, oConfig, null );
|
|
}
|
|
|
|
/* Provide a complete function to match the behaviour of the flash elements */
|
|
if ( oConfig.fnComplete !== null )
|
|
{
|
|
oConfig.fnComplete.call( that, nButton, oConfig, null, null );
|
|
}
|
|
|
|
that._fnCollectionHide( nButton, oConfig );
|
|
} );
|
|
},
|
|
|
|
/**
|
|
* Show print display
|
|
* @method _fnPrintStart
|
|
* @param {Event} e Event object
|
|
* @param {Object} oConfig Button configuration object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnPrintStart": function ( e, oConfig )
|
|
{
|
|
var that = this;
|
|
var oSetDT = this.s.dt;
|
|
|
|
/* Parse through the DOM hiding everything that isn't needed for the table */
|
|
this._fnPrintHideNodes( oSetDT.nTable );
|
|
|
|
/* Show the whole table */
|
|
this.s.print.saveStart = oSetDT._iDisplayStart;
|
|
this.s.print.saveLength = oSetDT._iDisplayLength;
|
|
|
|
if ( oConfig.bShowAll )
|
|
{
|
|
oSetDT._iDisplayStart = 0;
|
|
oSetDT._iDisplayLength = -1;
|
|
oSetDT.oApi._fnCalculateEnd( oSetDT );
|
|
oSetDT.oApi._fnDraw( oSetDT );
|
|
}
|
|
|
|
/* Adjust the display for scrolling which might be done by DataTables */
|
|
if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" )
|
|
{
|
|
this._fnPrintScrollStart( oSetDT );
|
|
}
|
|
|
|
/* Remove the other DataTables feature nodes - but leave the table! and info div */
|
|
var anFeature = oSetDT.aanFeatures;
|
|
for ( var cFeature in anFeature )
|
|
{
|
|
if ( cFeature != 'i' && cFeature != 't' && cFeature.length == 1 )
|
|
{
|
|
for ( var i=0, iLen=anFeature[cFeature].length ; i<iLen ; i++ )
|
|
{
|
|
this.dom.print.hidden.push( {
|
|
"node": anFeature[cFeature][i],
|
|
"display": "block"
|
|
} );
|
|
anFeature[cFeature][i].style.display = "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Print class can be used for styling */
|
|
$(document.body).addClass( 'DTTT_Print' );
|
|
|
|
/* Add a node telling the user what is going on */
|
|
if ( oConfig.sInfo !== "" )
|
|
{
|
|
var nInfo = document.createElement( "div" );
|
|
nInfo.className = "DTTT_print_info";
|
|
nInfo.innerHTML = oConfig.sInfo;
|
|
document.body.appendChild( nInfo );
|
|
|
|
setTimeout( function() {
|
|
$(nInfo).fadeOut( "normal", function() {
|
|
document.body.removeChild( nInfo );
|
|
} );
|
|
}, 2000 );
|
|
}
|
|
|
|
/* Add a message at the top of the page */
|
|
if ( oConfig.sMessage !== "" )
|
|
{
|
|
this.dom.print.message = document.createElement( "div" );
|
|
this.dom.print.message.className = "DTTT_PrintMessage";
|
|
this.dom.print.message.innerHTML = oConfig.sMessage;
|
|
document.body.insertBefore( this.dom.print.message, document.body.childNodes[0] );
|
|
}
|
|
|
|
/* Cache the scrolling and the jump to the top of the t=page */
|
|
this.s.print.saveScroll = $(window).scrollTop();
|
|
window.scrollTo( 0, 0 );
|
|
|
|
this.s.print.funcEnd = function(e) {
|
|
that._fnPrintEnd.call( that, e );
|
|
};
|
|
$(document).bind( "keydown", null, this.s.print.funcEnd );
|
|
},
|
|
|
|
|
|
/**
|
|
* Printing is finished, resume normal display
|
|
* @method _fnPrintEnd
|
|
* @param {Event} e Event object
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnPrintEnd": function ( e )
|
|
{
|
|
/* Only interested in the escape key */
|
|
if ( e.keyCode == 27 )
|
|
{
|
|
e.preventDefault();
|
|
|
|
var that = this;
|
|
var oSetDT = this.s.dt;
|
|
var oSetPrint = this.s.print;
|
|
var oDomPrint = this.dom.print;
|
|
|
|
/* Show all hidden nodes */
|
|
this._fnPrintShowNodes();
|
|
|
|
/* Restore DataTables' scrolling */
|
|
if ( oSetDT.oScroll.sX !== "" || oSetDT.oScroll.sY !== "" )
|
|
{
|
|
this._fnPrintScrollEnd();
|
|
}
|
|
|
|
/* Restore the scroll */
|
|
window.scrollTo( 0, oSetPrint.saveScroll );
|
|
|
|
/* Drop the print message */
|
|
if ( oDomPrint.message !== null )
|
|
{
|
|
document.body.removeChild( oDomPrint.message );
|
|
oDomPrint.message = null;
|
|
}
|
|
|
|
/* Styling class */
|
|
$(document.body).removeClass( 'DTTT_Print' );
|
|
|
|
/* Restore the table length */
|
|
oSetDT._iDisplayStart = oSetPrint.saveStart;
|
|
oSetDT._iDisplayLength = oSetPrint.saveLength;
|
|
oSetDT.oApi._fnCalculateEnd( oSetDT );
|
|
oSetDT.oApi._fnDraw( oSetDT );
|
|
|
|
$(document).unbind( "keydown", this.s.print.funcEnd );
|
|
this.s.print.funcEnd = null;
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Take account of scrolling in DataTables by showing the full table
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnPrintScrollStart": function ()
|
|
{
|
|
var
|
|
oSetDT = this.s.dt,
|
|
nScrollHeadInner = oSetDT.nScrollHead.getElementsByTagName('div')[0],
|
|
nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
|
|
nScrollBody = oSetDT.nTable.parentNode;
|
|
|
|
/* Copy the header in the thead in the body table, this way we show one single table when
|
|
* in print view. Note that this section of code is more or less verbatim from DT 1.7.0
|
|
*/
|
|
var nTheadSize = oSetDT.nTable.getElementsByTagName('thead');
|
|
if ( nTheadSize.length > 0 )
|
|
{
|
|
oSetDT.nTable.removeChild( nTheadSize[0] );
|
|
}
|
|
|
|
if ( oSetDT.nTFoot !== null )
|
|
{
|
|
var nTfootSize = oSetDT.nTable.getElementsByTagName('tfoot');
|
|
if ( nTfootSize.length > 0 )
|
|
{
|
|
oSetDT.nTable.removeChild( nTfootSize[0] );
|
|
}
|
|
}
|
|
|
|
nTheadSize = oSetDT.nTHead.cloneNode(true);
|
|
oSetDT.nTable.insertBefore( nTheadSize, oSetDT.nTable.childNodes[0] );
|
|
|
|
if ( oSetDT.nTFoot !== null )
|
|
{
|
|
nTfootSize = oSetDT.nTFoot.cloneNode(true);
|
|
oSetDT.nTable.insertBefore( nTfootSize, oSetDT.nTable.childNodes[1] );
|
|
}
|
|
|
|
/* Now adjust the table's viewport so we can actually see it */
|
|
if ( oSetDT.oScroll.sX !== "" )
|
|
{
|
|
oSetDT.nTable.style.width = $(oSetDT.nTable).outerWidth()+"px";
|
|
nScrollBody.style.width = $(oSetDT.nTable).outerWidth()+"px";
|
|
nScrollBody.style.overflow = "visible";
|
|
}
|
|
|
|
if ( oSetDT.oScroll.sY !== "" )
|
|
{
|
|
nScrollBody.style.height = $(oSetDT.nTable).outerHeight()+"px";
|
|
nScrollBody.style.overflow = "visible";
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Take account of scrolling in DataTables by showing the full table. Note that the redraw of
|
|
* the DataTable that we do will actually deal with the majority of the hardword here
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnPrintScrollEnd": function ()
|
|
{
|
|
var
|
|
oSetDT = this.s.dt,
|
|
nScrollBody = oSetDT.nTable.parentNode;
|
|
|
|
if ( oSetDT.oScroll.sX !== "" )
|
|
{
|
|
nScrollBody.style.width = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sX );
|
|
nScrollBody.style.overflow = "auto";
|
|
}
|
|
|
|
if ( oSetDT.oScroll.sY !== "" )
|
|
{
|
|
nScrollBody.style.height = oSetDT.oApi._fnStringToCss( oSetDT.oScroll.sY );
|
|
nScrollBody.style.overflow = "auto";
|
|
}
|
|
},
|
|
|
|
|
|
/**
|
|
* Resume the display of all TableTools hidden nodes
|
|
* @method _fnPrintShowNodes
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnPrintShowNodes": function ( )
|
|
{
|
|
var anHidden = this.dom.print.hidden;
|
|
|
|
for ( var i=0, iLen=anHidden.length ; i<iLen ; i++ )
|
|
{
|
|
anHidden[i].node.style.display = anHidden[i].display;
|
|
}
|
|
anHidden.splice( 0, anHidden.length );
|
|
},
|
|
|
|
|
|
/**
|
|
* Hide nodes which are not needed in order to display the table. Note that this function is
|
|
* recursive
|
|
* @method _fnPrintHideNodes
|
|
* @param {Node} nNode Element which should be showing in a 'print' display
|
|
* @returns void
|
|
* @private
|
|
*/
|
|
"_fnPrintHideNodes": function ( nNode )
|
|
{
|
|
var anHidden = this.dom.print.hidden;
|
|
|
|
var nParent = nNode.parentNode;
|
|
var nChildren = nParent.childNodes;
|
|
for ( var i=0, iLen=nChildren.length ; i<iLen ; i++ )
|
|
{
|
|
if ( nChildren[i] != nNode && nChildren[i].nodeType == 1 )
|
|
{
|
|
/* If our node is shown (don't want to show nodes which were previously hidden) */
|
|
var sDisplay = $(nChildren[i]).css("display");
|
|
if ( sDisplay != "none" )
|
|
{
|
|
/* Cache the node and it's previous state so we can restore it */
|
|
anHidden.push( {
|
|
"node": nChildren[i],
|
|
"display": sDisplay
|
|
} );
|
|
nChildren[i].style.display = "none";
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( nParent.nodeName != "BODY" )
|
|
{
|
|
this._fnPrintHideNodes( nParent );
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Static variables
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/**
|
|
* Store of all instances that have been created of TableTools, so one can look up other (when
|
|
* there is need of a master)
|
|
* @property _aInstances
|
|
* @type Array
|
|
* @default []
|
|
* @private
|
|
*/
|
|
TableTools._aInstances = [];
|
|
|
|
|
|
/**
|
|
* Store of all listeners and their callback functions
|
|
* @property _aListeners
|
|
* @type Array
|
|
* @default []
|
|
*/
|
|
TableTools._aListeners = [];
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Static methods
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/**
|
|
* Get an array of all the master instances
|
|
* @method fnGetMasters
|
|
* @returns {Array} List of master TableTools instances
|
|
* @static
|
|
*/
|
|
TableTools.fnGetMasters = function ()
|
|
{
|
|
var a = [];
|
|
for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ )
|
|
{
|
|
if ( TableTools._aInstances[i].s.master )
|
|
{
|
|
a.push( TableTools._aInstances[i] );
|
|
}
|
|
}
|
|
return a;
|
|
};
|
|
|
|
/**
|
|
* Get the master instance for a table node (or id if a string is given)
|
|
* @method fnGetInstance
|
|
* @returns {Object} ID of table OR table node, for which we want the TableTools instance
|
|
* @static
|
|
*/
|
|
TableTools.fnGetInstance = function ( node )
|
|
{
|
|
if ( typeof node != 'object' )
|
|
{
|
|
node = document.getElementById(node);
|
|
}
|
|
|
|
for ( var i=0, iLen=TableTools._aInstances.length ; i<iLen ; i++ )
|
|
{
|
|
if ( TableTools._aInstances[i].s.master && TableTools._aInstances[i].dom.table == node )
|
|
{
|
|
return TableTools._aInstances[i];
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
|
|
|
|
/**
|
|
* Add a listener for a specific event
|
|
* @method _fnEventListen
|
|
* @param {Object} that Scope of the listening function (i.e. 'this' in the caller)
|
|
* @param {String} type Event type
|
|
* @param {Function} fn Function
|
|
* @returns void
|
|
* @private
|
|
* @static
|
|
*/
|
|
TableTools._fnEventListen = function ( that, type, fn )
|
|
{
|
|
TableTools._aListeners.push( {
|
|
"that": that,
|
|
"type": type,
|
|
"fn": fn
|
|
} );
|
|
};
|
|
|
|
|
|
/**
|
|
* An event has occured - look up every listener and fire it off. We check that the event we are
|
|
* going to fire is attached to the same table (using the table node as reference) before firing
|
|
* @method _fnEventDispatch
|
|
* @param {Object} that Scope of the listening function (i.e. 'this' in the caller)
|
|
* @param {String} type Event type
|
|
* @param {Node} node Element that the event occured on (may be null)
|
|
* @returns void
|
|
* @private
|
|
* @static
|
|
*/
|
|
TableTools._fnEventDispatch = function ( that, type, node )
|
|
{
|
|
var listeners = TableTools._aListeners;
|
|
for ( var i=0, iLen=listeners.length ; i<iLen ; i++ )
|
|
{
|
|
if ( that.dom.table == listeners[i].that.dom.table && listeners[i].type == type )
|
|
{
|
|
listeners[i].fn( node );
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Constants
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
/**
|
|
* @namespace Default button configurations
|
|
*/
|
|
TableTools.BUTTONS = {
|
|
"csv": {
|
|
"sAction": "flash_save",
|
|
"sCharSet": "utf8",
|
|
"bBomInc": false,
|
|
"sFileName": "*.csv",
|
|
"sFieldBoundary": '"',
|
|
"sFieldSeperator": ",",
|
|
"sNewLine": "auto",
|
|
"sTitle": "",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_csv",
|
|
"sButtonClassHover": "DTTT_button_csv_hover",
|
|
"sButtonText": "CSV",
|
|
"mColumns": "all", /* "all", "visible", "hidden" or array of column integers */
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"bSelectedOnly": false,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": function( nButton, oConfig, flash ) {
|
|
this.fnSetText( flash, this.fnGetTableData(oConfig) );
|
|
},
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
},
|
|
"xls": {
|
|
"sAction": "flash_save",
|
|
"sCharSet": "utf16le",
|
|
"bBomInc": true,
|
|
"sFileName": "*.csv",
|
|
"sFieldBoundary": "",
|
|
"sFieldSeperator": "\t",
|
|
"sNewLine": "auto",
|
|
"sTitle": "",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_xls",
|
|
"sButtonClassHover": "DTTT_button_xls_hover",
|
|
"sButtonText": "Excel",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"bSelectedOnly": false,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": function( nButton, oConfig, flash ) {
|
|
this.fnSetText( flash, this.fnGetTableData(oConfig) );
|
|
},
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
},
|
|
"copy": {
|
|
"sAction": "flash_copy",
|
|
"sFieldBoundary": "",
|
|
"sFieldSeperator": "\t",
|
|
"sNewLine": "auto",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_copy",
|
|
"sButtonClassHover": "DTTT_button_copy_hover",
|
|
"sButtonText": "Copy",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"bSelectedOnly": false,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": function( nButton, oConfig, flash ) {
|
|
this.fnSetText( flash, this.fnGetTableData(oConfig) );
|
|
},
|
|
"fnSelect": null,
|
|
"fnComplete": function(nButton, oConfig, flash, text) {
|
|
var
|
|
lines = text.split('\n').length,
|
|
len = this.s.dt.nTFoot === null ? lines-1 : lines-2,
|
|
plural = (len==1) ? "" : "s";
|
|
alert( 'Copied '+len+' row'+plural+' to the clipboard' );
|
|
},
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
},
|
|
"pdf": {
|
|
"sAction": "flash_pdf",
|
|
"sFieldBoundary": "",
|
|
"sFieldSeperator": "\t",
|
|
"sNewLine": "\n",
|
|
"sFileName": "*.pdf",
|
|
"sToolTip": "",
|
|
"sTitle": "",
|
|
"sButtonClass": "DTTT_button_pdf",
|
|
"sButtonClassHover": "DTTT_button_pdf_hover",
|
|
"sButtonText": "PDF",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": false,
|
|
"bSelectedOnly": false,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"sPdfOrientation": "portrait",
|
|
"sPdfSize": "A4",
|
|
"sPdfMessage": "",
|
|
"fnClick": function( nButton, oConfig, flash ) {
|
|
this.fnSetText( flash,
|
|
"title:"+ this.fnGetTitle(oConfig) +"\n"+
|
|
"message:"+ oConfig.sPdfMessage +"\n"+
|
|
"colWidth:"+ this.fnCalcColRatios(oConfig) +"\n"+
|
|
"orientation:"+ oConfig.sPdfOrientation +"\n"+
|
|
"size:"+ oConfig.sPdfSize +"\n"+
|
|
"--/TableToolsOpts--\n" +
|
|
this.fnGetTableData(oConfig)
|
|
);
|
|
},
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
},
|
|
"print": {
|
|
"sAction": "print",
|
|
"sInfo": "<h6>Print view</h6><p>Please use your browser's print function to "+
|
|
"print this table. Press escape when finished.",
|
|
"sMessage": "",
|
|
"bShowAll": true,
|
|
"sToolTip": "View print view",
|
|
"sButtonClass": "DTTT_button_print",
|
|
"sButtonClassHover": "DTTT_button_print_hover",
|
|
"sButtonText": "Print",
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": null,
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
},
|
|
"text": {
|
|
"sAction": "text",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_text",
|
|
"sButtonClassHover": "DTTT_button_text_hover",
|
|
"sButtonText": "Text button",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"bSelectedOnly": false,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": null,
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
},
|
|
"select": {
|
|
"sAction": "text",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_text",
|
|
"sButtonClassHover": "DTTT_button_text_hover",
|
|
"sButtonText": "Select button",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": null,
|
|
"fnSelect": function( nButton, oConfig ) {
|
|
if ( this.fnGetSelected().length !== 0 ) {
|
|
$(nButton).removeClass('DTTT_disabled');
|
|
} else {
|
|
$(nButton).addClass('DTTT_disabled');
|
|
}
|
|
},
|
|
"fnComplete": null,
|
|
"fnInit": function( nButton, oConfig ) {
|
|
$(nButton).addClass('DTTT_disabled');
|
|
},
|
|
"fnCellRender": null
|
|
},
|
|
"select_single": {
|
|
"sAction": "text",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_text",
|
|
"sButtonClassHover": "DTTT_button_text_hover",
|
|
"sButtonText": "Select button",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": null,
|
|
"fnSelect": function( nButton, oConfig ) {
|
|
var iSelected = this.fnGetSelected().length;
|
|
if ( iSelected == 1 ) {
|
|
$(nButton).removeClass('DTTT_disabled');
|
|
} else {
|
|
$(nButton).addClass('DTTT_disabled');
|
|
}
|
|
},
|
|
"fnComplete": null,
|
|
"fnInit": function( nButton, oConfig ) {
|
|
$(nButton).addClass('DTTT_disabled');
|
|
},
|
|
"fnCellRender": null
|
|
},
|
|
"select_all": {
|
|
"sAction": "text",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_text",
|
|
"sButtonClassHover": "DTTT_button_text_hover",
|
|
"sButtonText": "Select all",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": function( nButton, oConfig ) {
|
|
this.fnSelectAll();
|
|
},
|
|
"fnSelect": function( nButton, oConfig ) {
|
|
if ( this.fnGetSelected().length == this.s.dt.fnRecordsDisplay() ) {
|
|
$(nButton).addClass('DTTT_disabled');
|
|
} else {
|
|
$(nButton).removeClass('DTTT_disabled');
|
|
}
|
|
},
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
},
|
|
"select_none": {
|
|
"sAction": "text",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_text",
|
|
"sButtonClassHover": "DTTT_button_text_hover",
|
|
"sButtonText": "Deselect all",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": function( nButton, oConfig ) {
|
|
this.fnSelectNone();
|
|
},
|
|
"fnSelect": function( nButton, oConfig ) {
|
|
if ( this.fnGetSelected().length !== 0 ) {
|
|
$(nButton).removeClass('DTTT_disabled');
|
|
} else {
|
|
$(nButton).addClass('DTTT_disabled');
|
|
}
|
|
},
|
|
"fnComplete": null,
|
|
"fnInit": function( nButton, oConfig ) {
|
|
$(nButton).addClass('DTTT_disabled');
|
|
},
|
|
"fnCellRender": null
|
|
},
|
|
"ajax": {
|
|
"sAction": "text",
|
|
"sFieldBoundary": "",
|
|
"sFieldSeperator": "\t",
|
|
"sNewLine": "\n",
|
|
"sAjaxUrl": "/xhr.php",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_text",
|
|
"sButtonClassHover": "DTTT_button_text_hover",
|
|
"sButtonText": "Ajax button",
|
|
"mColumns": "all",
|
|
"bHeader": true,
|
|
"bFooter": true,
|
|
"bSelectedOnly": false,
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": function( nButton, oConfig ) {
|
|
var sData = this.fnGetTableData(oConfig);
|
|
$.ajax( {
|
|
"url": oConfig.sAjaxUrl,
|
|
"data": [
|
|
{ "name": "tableData", "value": sData }
|
|
],
|
|
"success": oConfig.fnAjaxComplete,
|
|
"dataType": "json",
|
|
"type": "POST",
|
|
"cache": false,
|
|
"error": function () {
|
|
alert( "Error detected when sending table data to server" );
|
|
}
|
|
} );
|
|
},
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnAjaxComplete": function( json ) {
|
|
alert( 'Ajax complete' );
|
|
},
|
|
"fnCellRender": null
|
|
},
|
|
"div": {
|
|
"sAction": "div",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_nonbutton",
|
|
"sButtonClassHover": "",
|
|
"sButtonText": "Text button",
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": null,
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"nContent": null,
|
|
"fnCellRender": null
|
|
},
|
|
"collection": {
|
|
"sAction": "collection",
|
|
"sToolTip": "",
|
|
"sButtonClass": "DTTT_button_collection",
|
|
"sButtonClassHover": "DTTT_button_collection_hover",
|
|
"sButtonText": "Collection",
|
|
"fnMouseover": null,
|
|
"fnMouseout": null,
|
|
"fnClick": function( nButton, oConfig ) {
|
|
this._fnCollectionShow(nButton, oConfig);
|
|
},
|
|
"fnSelect": null,
|
|
"fnComplete": null,
|
|
"fnInit": null,
|
|
"fnCellRender": null
|
|
}
|
|
};
|
|
/*
|
|
* on* callback parameters:
|
|
* 1. node - button element
|
|
* 2. object - configuration object for this button
|
|
* 3. object - ZeroClipboard reference (flash button only)
|
|
* 4. string - Returned string from Flash (flash button only - and only on 'complete')
|
|
*/
|
|
|
|
|
|
/**
|
|
* @namespace TableTools default settings for initialisation
|
|
*/
|
|
TableTools.DEFAULTS = {
|
|
"sSwfPath": "media/swf/copy_cvs_xls_pdf.swf",
|
|
"sRowSelect": "none",
|
|
"sSelectedClass": "DTTT_selected",
|
|
"fnPreRowSelect": null,
|
|
"fnRowSelected": null,
|
|
"fnRowDeselected": null,
|
|
"aButtons": [ "copy", "csv", "xls", "pdf", "print" ]
|
|
};
|
|
|
|
|
|
/**
|
|
* Name of this class
|
|
* @constant CLASS
|
|
* @type String
|
|
* @default TableTools
|
|
*/
|
|
TableTools.prototype.CLASS = "TableTools";
|
|
|
|
|
|
/**
|
|
* TableTools version
|
|
* @constant VERSION
|
|
* @type String
|
|
* @default 2.0.2
|
|
*/
|
|
TableTools.VERSION = "2.0.2";
|
|
TableTools.prototype.VERSION = TableTools.VERSION;
|
|
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* Initialisation
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*
|
|
* Register a new feature with DataTables
|
|
*/
|
|
if ( typeof $.fn.dataTable == "function" &&
|
|
typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
|
|
$.fn.dataTableExt.fnVersionCheck('1.8.2') )
|
|
{
|
|
$.fn.dataTableExt.aoFeatures.push( {
|
|
"fnInit": function( oDTSettings ) {
|
|
var oOpts = typeof oDTSettings.oInit.oTableTools != 'undefined' ?
|
|
oDTSettings.oInit.oTableTools : {};
|
|
|
|
var oTT = new TableTools( oDTSettings.oInstance, oOpts );
|
|
TableTools._aInstances.push( oTT );
|
|
|
|
return oTT.dom.container;
|
|
},
|
|
"cFeature": "T",
|
|
"sFeature": "TableTools"
|
|
} );
|
|
}
|
|
else
|
|
{
|
|
alert( "Warning: TableTools 2 requires DataTables 1.8.2 or newer - www.datatables.net/download");
|
|
}
|
|
|
|
})(jQuery, window, document);
|