diff --git a/NzbDrone.Web/Content/DataTables-1.9.0/media/css/jquery.dataTables.css b/NzbDrone.Web/Content/DataTables-1.9.0/media/css/jquery.dataTables.css
index d28a261df..ddd272f9d 100644
--- a/NzbDrone.Web/Content/DataTables-1.9.0/media/css/jquery.dataTables.css
+++ b/NzbDrone.Web/Content/DataTables-1.9.0/media/css/jquery.dataTables.css
@@ -28,11 +28,19 @@ table.dataTable thead th {
*cursor: hand;
}
-table.dataTable tfoot th
-{
- padding: 3px 18px 3px 10px;
- border-top: 1px solid black;
- font-weight: bold;
+table.dataTable tfoot th {
+ font-family: "Segoe UI Light" , "Open Sans" , "Segoe UI" , sans-serif;
+ border-width: 300;
+ font-size: 17px;
+ padding: 2px;
+ border-style: none;
+ border-color: #EEEEEE;
+ padding-left: 7px;
+ text-align: left;
+ background-color: white;
+ font-weight: lighter;
+ cursor: pointer;
+ *cursor: hand;
}
table.dataTable td {
diff --git a/NzbDrone.Web/Content/SeriesEditor.css b/NzbDrone.Web/Content/SeriesEditor.css
new file mode 100644
index 000000000..be5178250
--- /dev/null
+++ b/NzbDrone.Web/Content/SeriesEditor.css
@@ -0,0 +1,60 @@
+.masterControls {
+ margin-top: 10px;
+ overflow: hidden;
+}
+
+.checkboxColumn {
+ width: 110px;
+ text-align: center;
+}
+
+.buttons {
+ width: 600px;
+ text-align: center;
+}
+
+table input[type="text"], table select {
+ margin: 2px 2px;
+}
+
+td .path {
+ width: 300px;
+}
+
+td .backlogSetting {
+ width: 100px;
+}
+
+td .quality {
+ width: 120px;
+}
+
+th .footer-control {
+ width: 100px;
+}
+
+th .footer-control-quality {
+ width: 120px;
+}
+
+#stylized, .settingsForm {
+ overflow: hidden;
+}
+
+#stylized {
+ float: left;
+}
+
+#changesOverview {
+ margin-top: 15px;
+ float: left;
+ font-size: 20px;
+}
+
+#seriesEditorGrid tfoot {
+ background-color: lightgrey;
+}
+
+#editToggleMaster {
+ margin-left: 5px;
+}
\ No newline at end of file
diff --git a/NzbDrone.Web/Controllers/AddSeriesController.cs b/NzbDrone.Web/Controllers/AddSeriesController.cs
index 84cf0c434..4b164671c 100644
--- a/NzbDrone.Web/Controllers/AddSeriesController.cs
+++ b/NzbDrone.Web/Controllers/AddSeriesController.cs
@@ -11,6 +11,7 @@ using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using NzbDrone.Web.Filters;
using NzbDrone.Web.Models;
+using TvdbLib.Exceptions;
namespace NzbDrone.Web.Controllers
{
@@ -186,18 +187,34 @@ namespace NzbDrone.Web.Controllers
[HttpGet]
public JsonResult LookupSeries(string term)
{
- var tvDbResults = _tvDbProvider.SearchSeries(term).Select(r => new TvDbSearchResultModel
- {
- Id = r.Id,
- Title = r.SeriesName,
- DisplayedTitle = r.FirstAired.Year > 1900 && !r.SeriesName.EndsWith("(" + r.FirstAired.Year + ")")
- ?string.Format("{0} ({1})", r.SeriesName, r.FirstAired.Year)
- :r.SeriesName,
- Banner = r.Banner.BannerPath,
- Url = String.Format("http://www.thetvdb.com/?tab=series&id={0}", r.Id)
- }).ToList();
-
- return Json(tvDbResults, JsonRequestBehavior.AllowGet);
+ try
+ {
+ var tvDbResults = _tvDbProvider.SearchSeries(term).Select(r => new TvDbSearchResultModel
+ {
+ Id = r.Id,
+ Title = r.SeriesName,
+ DisplayedTitle = r.FirstAired.Year > 1900 && !r.SeriesName.EndsWith("(" + r.FirstAired.Year + ")")
+ ? string.Format("{0} ({1})", r.SeriesName, r.FirstAired.Year)
+ : r.SeriesName,
+ Banner = r.Banner.BannerPath,
+ Url = String.Format("http://www.thetvdb.com/?tab=series&id={0}", r.Id)
+ }).ToList();
+
+ return Json(tvDbResults, JsonRequestBehavior.AllowGet);
+ }
+
+ catch(TvdbNotAvailableException ex)
+ {
+ logger.WarnException("Unable to lookup series on TheTVDB", ex);
+ return JsonNotificationResult.Info("Lookup Failed", "TheTVDB is not available at this time.");
+ }
+
+ catch(Exception ex)
+ {
+ logger.WarnException("Unknown Error when looking up series on TheTVDB", ex);
+ return JsonNotificationResult.Info("Lookup Failed", "Unknown error while connecting to TheTVDB");
+ }
+
}
public ActionResult RootList()
diff --git a/NzbDrone.Web/NzbDrone.Web.csproj b/NzbDrone.Web/NzbDrone.Web.csproj
index ffcc32816..1aaeb81f9 100644
--- a/NzbDrone.Web/NzbDrone.Web.csproj
+++ b/NzbDrone.Web/NzbDrone.Web.csproj
@@ -153,6 +153,7 @@
+
@@ -360,6 +361,8 @@
+
+
@@ -388,6 +391,7 @@
+
diff --git a/NzbDrone.Web/Scripts/DataTables-1.9.0/media/js/FixedHeader.js b/NzbDrone.Web/Scripts/DataTables-1.9.0/media/js/FixedHeader.js
new file mode 100644
index 000000000..bb20a8ae6
--- /dev/null
+++ b/NzbDrone.Web/Scripts/DataTables-1.9.0/media/js/FixedHeader.js
@@ -0,0 +1,937 @@
+/*
+ * File: FixedHeader.js
+ * Version: 2.0.6
+ * Description: "Fix" a header at the top of the table, so it scrolls with the table
+ * Author: Allan Jardine (www.sprymedia.co.uk)
+ * Created: Wed 16 Sep 2009 19:46:30 BST
+ * Language: Javascript
+ * License: GPL v2 or BSD 3 point style
+ * Project: Just a little bit of fun - enjoy :-)
+ * Contact: www.sprymedia.co.uk/contact
+ *
+ * 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
+ */
+
+/*
+ * Function: FixedHeader
+ * Purpose: Provide 'fixed' header, footer and columns on an HTML table
+ * Returns: object:FixedHeader - must be called with 'new'
+ * Inputs: mixed:mTable - target table
+ * 1. DataTable object - when using FixedHeader with DataTables, or
+ * 2. HTML table node - when using FixedHeader without DataTables
+ * object:oInit - initialisation settings, with the following properties (each optional)
+ * bool:top - fix the header (default true)
+ * bool:bottom - fix the footer (default false)
+ * bool:left - fix the left most column (default false)
+ * bool:right - fix the right most column (default false)
+ * int:zTop - fixed header zIndex
+ * int:zBottom - fixed footer zIndex
+ * int:zLeft - fixed left zIndex
+ * int:zRight - fixed right zIndex
+ */
+var FixedHeader = function ( mTable, oInit ) {
+ /* Sanity check - you just know it will happen */
+ if ( typeof this.fnInit != 'function' )
+ {
+ alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." );
+ return;
+ }
+
+ var that = this;
+ var oSettings = {
+ "aoCache": [],
+ "oSides": {
+ "top": true,
+ "bottom": false,
+ "left": false,
+ "right": false
+ },
+ "oZIndexes": {
+ "top": 104,
+ "bottom": 103,
+ "left": 102,
+ "right": 101
+ },
+ "oMes": {
+ "iTableWidth": 0,
+ "iTableHeight": 0,
+ "iTableLeft": 0,
+ "iTableRight": 0, /* note this is left+width, not actually "right" */
+ "iTableTop": 0,
+ "iTableBottom": 0 /* note this is top+height, not actually "bottom" */
+ },
+ "oOffset": {
+ "top": 0
+ },
+ "nTable": null,
+ "bUseAbsPos": false,
+ "bFooter": false
+ };
+
+ /*
+ * Function: fnGetSettings
+ * Purpose: Get the settings for this object
+ * Returns: object: - settings object
+ * Inputs: -
+ */
+ this.fnGetSettings = function () {
+ return oSettings;
+ };
+
+ /*
+ * Function: fnUpdate
+ * Purpose: Update the positioning and copies of the fixed elements
+ * Returns: -
+ * Inputs: -
+ */
+ this.fnUpdate = function () {
+ this._fnUpdateClones();
+ this._fnUpdatePositions();
+ };
+
+ /*
+ * Function: fnPosition
+ * Purpose: Update the positioning of the fixed elements
+ * Returns: -
+ * Inputs: -
+ */
+ this.fnPosition = function () {
+ this._fnUpdatePositions();
+ };
+
+ /* Let's do it */
+ this.fnInit( mTable, oInit );
+
+ /* Store the instance on the DataTables object for easy access */
+ if ( typeof mTable.fnSettings == 'function' )
+ {
+ mTable._oPluginFixedHeader = this;
+ }
+};
+
+
+/*
+ * Variable: FixedHeader
+ * Purpose: Prototype for FixedHeader
+ * Scope: global
+ */
+FixedHeader.prototype = {
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Initialisation
+ */
+
+ /*
+ * Function: fnInit
+ * Purpose: The "constructor"
+ * Returns: -
+ * Inputs: {as FixedHeader function}
+ */
+ fnInit: function ( oTable, oInit )
+ {
+ var s = this.fnGetSettings();
+ var that = this;
+
+ /* Record the user definable settings */
+ this.fnInitSettings( s, oInit );
+
+ /* DataTables specific stuff */
+ if ( typeof oTable.fnSettings == 'function' )
+ {
+ if ( typeof oTable.fnVersionCheck == 'functon' &&
+ oTable.fnVersionCheck( '1.6.0' ) !== true )
+ {
+ alert( "FixedHeader 2 required DataTables 1.6.0 or later. "+
+ "Please upgrade your DataTables installation" );
+ return;
+ }
+
+ var oDtSettings = oTable.fnSettings();
+
+ if ( oDtSettings.oScroll.sX != "" || oDtSettings.oScroll.sY != "" )
+ {
+ alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" );
+ return;
+ }
+
+ s.nTable = oDtSettings.nTable;
+ oDtSettings.aoDrawCallback.push( {
+ "fn": function () {
+ FixedHeader.fnMeasure();
+ that._fnUpdateClones.call(that);
+ that._fnUpdatePositions.call(that);
+ },
+ "sName": "FixedHeader"
+ } );
+ }
+ else
+ {
+ s.nTable = oTable;
+ }
+
+ s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false;
+
+ /* "Detect" browsers that don't support absolute positioing - or have bugs */
+ s.bUseAbsPos = (jQuery.browser.msie && (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0"));
+
+ /* Add the 'sides' that are fixed */
+ if ( s.oSides.top )
+ {
+ s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) );
+ }
+ if ( s.oSides.bottom )
+ {
+ s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) );
+ }
+ if ( s.oSides.left )
+ {
+ s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft ) );
+ }
+ if ( s.oSides.right )
+ {
+ s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight ) );
+ }
+
+ /* Event listeners for window movement */
+ FixedHeader.afnScroll.push( function () {
+ that._fnUpdatePositions.call(that);
+ } );
+
+ jQuery(window).resize( function () {
+ FixedHeader.fnMeasure();
+ that._fnUpdateClones.call(that);
+ that._fnUpdatePositions.call(that);
+ } );
+
+ /* Get things right to start with */
+ FixedHeader.fnMeasure();
+ that._fnUpdateClones();
+ that._fnUpdatePositions();
+ },
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Support functions
+ */
+
+ /*
+ * Function: fnInitSettings
+ * Purpose: Take the user's settings and copy them to our local store
+ * Returns: -
+ * Inputs: object:s - the local settings object
+ * object:oInit - the user's settings object
+ */
+ fnInitSettings: function ( s, oInit )
+ {
+ if ( typeof oInit != 'undefined' )
+ {
+ if ( typeof oInit.top != 'undefined' ) {
+ s.oSides.top = oInit.top;
+ }
+ if ( typeof oInit.bottom != 'undefined' ) {
+ s.oSides.bottom = oInit.bottom;
+ }
+ if ( typeof oInit.left != 'undefined' ) {
+ s.oSides.left = oInit.left;
+ }
+ if ( typeof oInit.right != 'undefined' ) {
+ s.oSides.right = oInit.right;
+ }
+
+ if ( typeof oInit.zTop != 'undefined' ) {
+ s.oZIndexes.top = oInit.zTop;
+ }
+ if ( typeof oInit.zBottom != 'undefined' ) {
+ s.oZIndexes.bottom = oInit.zBottom;
+ }
+ if ( typeof oInit.zLeft != 'undefined' ) {
+ s.oZIndexes.left = oInit.zLeft;
+ }
+ if ( typeof oInit.zRight != 'undefined' ) {
+ s.oZIndexes.right = oInit.zRight;
+ }
+
+ if ( typeof oInit.offsetTop != 'undefined' ) {
+ s.oOffset.top = oInit.offsetTop;
+ }
+ }
+
+ /* Detect browsers which have poor position:fixed support so we can use absolute positions.
+ * This is much slower since the position must be updated for each scroll, but widens
+ * compatibility
+ */
+ s.bUseAbsPos = (jQuery.browser.msie &&
+ (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0"));
+ },
+
+ /*
+ * Function: _fnCloneTable
+ * Purpose: Clone the table node and do basic initialisation
+ * Returns: -
+ * Inputs: -
+ */
+ _fnCloneTable: function ( sType, sClass, fnClone )
+ {
+ var s = this.fnGetSettings();
+ var nCTable;
+
+ /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how
+ * DataTables works. Therefore, we can set this to be relatively position (if it is not
+ * alreadu absolute, and use this as the base point for the cloned header
+ */
+ if ( jQuery(s.nTable.parentNode).css('position') != "absolute" )
+ {
+ s.nTable.parentNode.style.position = "relative";
+ }
+
+ /* Just a shallow clone will do - we only want the table node */
+ nCTable = s.nTable.cloneNode( false );
+ nCTable.removeAttribute( 'id' );
+
+ var nDiv = document.createElement( 'div' );
+ nDiv.style.position = "absolute";
+ nDiv.style.top = "0px";
+ nDiv.style.left = "0px";
+ nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass;
+
+ /* Set the zIndexes */
+ if ( sType == "fixedHeader" )
+ {
+ nDiv.style.zIndex = s.oZIndexes.top;
+ }
+ if ( sType == "fixedFooter" )
+ {
+ nDiv.style.zIndex = s.oZIndexes.bottom;
+ }
+ if ( sType == "fixedLeft" )
+ {
+ nDiv.style.zIndex = s.oZIndexes.left;
+ }
+ else if ( sType == "fixedRight" )
+ {
+ nDiv.style.zIndex = s.oZIndexes.right;
+ }
+
+ /* remove margins since we are going to poistion it absolutely */
+ nCTable.style.margin = "0";
+
+ /* Insert the newly cloned table into the DOM, on top of the "real" header */
+ nDiv.appendChild( nCTable );
+ document.body.appendChild( nDiv );
+
+ return {
+ "nNode": nCTable,
+ "nWrapper": nDiv,
+ "sType": sType,
+ "sPosition": "",
+ "sTop": "",
+ "sLeft": "",
+ "fnClone": fnClone
+ };
+ },
+
+ /*
+ * Function: _fnUpdatePositions
+ * Purpose: Get the current positioning of the table in the DOM
+ * Returns: -
+ * Inputs: -
+ */
+ _fnMeasure: function ()
+ {
+ var
+ s = this.fnGetSettings(),
+ m = s.oMes,
+ jqTable = jQuery(s.nTable),
+ oOffset = jqTable.offset(),
+ iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ),
+ iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' );
+
+ m.iTableWidth = jqTable.outerWidth();
+ m.iTableHeight = jqTable.outerHeight();
+ m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft;
+ m.iTableTop = oOffset.top + iParentScrollTop;
+ m.iTableRight = m.iTableLeft + m.iTableWidth;
+ m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth;
+ m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight;
+ },
+
+ /*
+ * Function: _fnSumScroll
+ * Purpose: Sum node parameters all the way to the top
+ * Returns: int: sum
+ * Inputs: node:n - node to consider
+ * string:side - scrollTop or scrollLeft
+ */
+ _fnSumScroll: function ( n, side )
+ {
+ var i = n[side];
+ while ( n = n.parentNode )
+ {
+ if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' )
+ {
+ break;
+ }
+ i = n[side];
+ }
+ return i;
+ },
+
+ /*
+ * Function: _fnUpdatePositions
+ * Purpose: Loop over the fixed elements for this table and update their positions
+ * Returns: -
+ * Inputs: -
+ */
+ _fnUpdatePositions: function ()
+ {
+ var s = this.fnGetSettings();
+ this._fnMeasure();
+
+ for ( var i=0, iLen=s.aoCache.length ; i oWin.iScrollTop + s.oOffset.top )
+ {
+ /* Above the table */
+ this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
+ this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style );
+ this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+ }
+ else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight )
+ {
+ /* At the bottom of the table */
+ this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
+ this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style );
+ this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+ }
+ else
+ {
+ /* In the middle of the table */
+ if ( s.bUseAbsPos )
+ {
+ this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style );
+ this._fnUpdateCache( oCache, 'sTop', oWin.iScrollTop+"px", 'top', nTable.style );
+ this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style );
+ }
+ else
+ {
+ this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style );
+ this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style );
+ this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style );
+ }
+ }
+ },
+
+ /*
+ * Function: _fnUpdateCache
+ * Purpose: Check the cache and update cache and value if needed
+ * Returns: -
+ * Inputs: object:oCache - local cache object
+ * string:sCache - cache property
+ * string:sSet - value to set
+ * string:sProperty - object property to set
+ * object:oObj - object to update
+ */
+ _fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj )
+ {
+ if ( oCache[sCache] != sSet )
+ {
+ oObj[sProperty] = sSet;
+ oCache[sCache] = sSet;
+ }
+ },
+
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Cloning functions
+ */
+
+ /*
+ * Function: _fnCloneThead
+ * Purpose: Clone the thead element
+ * Returns: -
+ * Inputs: object:oCache - the cahced values for this fixed element
+ */
+ _fnCloneThead: function ( oCache )
+ {
+ var s = this.fnGetSettings();
+ var nTable = oCache.nNode;
+
+ /* Set the wrapper width to match that of the cloned table */
+ oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px";
+
+ /* Remove any children the cloned table has */
+ while ( nTable.childNodes.length > 0 )
+ {
+ jQuery('thead th', nTable).unbind( 'click' );
+ nTable.removeChild( nTable.childNodes[0] );
+ }
+
+ /* Clone the DataTables header */
+ var nThead = jQuery('thead', s.nTable).clone(true)[0];
+ nTable.appendChild( nThead );
+
+ /* Copy the widths across - apparently a clone isn't good enough for this */
+ jQuery("thead>tr th", s.nTable).each( function (i) {
+ jQuery("thead>tr th:eq("+i+")", nTable).width( jQuery(this).width() );
+ } );
+
+ jQuery("thead>tr td", s.nTable).each( function (i) {
+ jQuery("thead>tr td:eq("+i+")", nTable).width( jQuery(this).width() );
+ } );
+ },
+
+ /*
+ * Function: _fnCloneTfoot
+ * Purpose: Clone the tfoot element
+ * Returns: -
+ * Inputs: object:oCache - the cahced values for this fixed element
+ */
+ _fnCloneTfoot: function ( oCache )
+ {
+ var s = this.fnGetSettings();
+ var nTable = oCache.nNode;
+
+ /* Set the wrapper width to match that of the cloned table */
+ oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px";
+
+ /* Remove any children the cloned table has */
+ while ( nTable.childNodes.length > 0 )
+ {
+ nTable.removeChild( nTable.childNodes[0] );
+ }
+
+ /* Clone the DataTables footer */
+ var nTfoot = jQuery('tfoot', s.nTable).clone(true)[0];
+ nTable.appendChild( nTfoot );
+
+ /* Copy the widths across - apparently a clone isn't good enough for this */
+ jQuery("tfoot:eq(0)>tr th", s.nTable).each( function (i) {
+ jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( jQuery(this).width() );
+ } );
+
+ jQuery("tfoot:eq(0)>tr td", s.nTable).each( function (i) {
+ jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable)[0].style.width( jQuery(this).width() );
+ } );
+ },
+
+ /*
+ * Function: _fnCloneTLeft
+ * Purpose: Clone the left column
+ * Returns: -
+ * Inputs: object:oCache - the cached values for this fixed element
+ */
+ _fnCloneTLeft: function ( oCache )
+ {
+ var s = this.fnGetSettings();
+ var nTable = oCache.nNode;
+ var nBody = $('tbody', s.nTable)[0];
+ var iCols = $('tbody tr:eq(0) td', s.nTable).length;
+ var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0"));
+
+ /* Remove any children the cloned table has */
+ while ( nTable.childNodes.length > 0 )
+ {
+ nTable.removeChild( nTable.childNodes[0] );
+ }
+
+ /* Is this the most efficient way to do this - it looks horrible... */
+ nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] );
+ nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] );
+ if ( s.bFooter )
+ {
+ nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] );
+ }
+
+ /* Remove unneeded cells */
+ $('thead tr', nTable).each( function (k) {
+ $('th:gt(0)', this).remove();
+ } );
+
+ $('tfoot tr', nTable).each( function (k) {
+ $('th:gt(0)', this).remove();
+ } );
+
+ $('tbody tr', nTable).each( function (k) {
+ $('td:gt(0)', this).remove();
+ } );
+
+ this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
+
+ var iWidth = jQuery('thead tr th:eq(0)', s.nTable).outerWidth();
+ nTable.style.width = iWidth+"px";
+ oCache.nWrapper.style.width = iWidth+"px";
+ },
+
+ /*
+ * Function: _fnCloneTRight
+ * Purpose: Clone the right most colun
+ * Returns: -
+ * Inputs: object:oCache - the cahced values for this fixed element
+ */
+ _fnCloneTRight: function ( oCache )
+ {
+ var s = this.fnGetSettings();
+ var nBody = $('tbody', s.nTable)[0];
+ var nTable = oCache.nNode;
+ var iCols = jQuery('tbody tr:eq(0) td', s.nTable).length;
+ var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0"));
+
+ /* Remove any children the cloned table has */
+ while ( nTable.childNodes.length > 0 )
+ {
+ nTable.removeChild( nTable.childNodes[0] );
+ }
+
+ /* Is this the most efficient way to do this - it looks horrible... */
+ nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] );
+ nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] );
+ if ( s.bFooter )
+ {
+ nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] );
+ }
+ jQuery('thead tr th:not(:nth-child('+iCols+'n))', nTable).remove();
+ jQuery('tfoot tr th:not(:nth-child('+iCols+'n))', nTable).remove();
+
+ /* Remove unneeded cells */
+ $('tbody tr', nTable).each( function (k) {
+ $('td:lt('+(iCols-1)+')', this).remove();
+ } );
+
+ this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable );
+
+ var iWidth = jQuery('thead tr th:eq('+(iCols-1)+')', s.nTable).outerWidth();
+ nTable.style.width = iWidth+"px";
+ oCache.nWrapper.style.width = iWidth+"px";
+ },
+
+
+ /**
+ * Equalise the heights of the rows in a given table node in a cross browser way. Note that this
+ * is more or less lifted as is from FixedColumns
+ * @method fnEqualiseHeights
+ * @returns void
+ * @param {string} parent Node type - thead, tbody or tfoot
+ * @param {element} original Original node to take the heights from
+ * @param {element} clone Copy the heights to
+ * @private
+ */
+ "fnEqualiseHeights": function ( parent, original, clone )
+ {
+ var that = this,
+ jqBoxHack = $(parent+' tr:eq(0)', original).children(':eq(0)'),
+ iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(),
+ bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0"));
+
+ /* Remove cells which are not needed and copy the height from the original table */
+ $(parent+' tr', clone).each( function (k) {
+ /* Can we use some kind of object detection here?! This is very nasty - damn browsers */
+ if ( $.browser.mozilla || $.browser.opera )
+ {
+ $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() );
+ }
+ else
+ {
+ $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() - iBoxHack );
+ }
+
+ if ( !bRubbishOldIE )
+ {
+ $(parent+' tr:eq('+k+')', original).height( $(parent+' tr:eq('+k+')', original).outerHeight() );
+ }
+ } );
+ }
+};
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Static properties and methods
+ * We use these for speed! This information is common to all instances of FixedHeader, so no
+ * point if having them calculated and stored for each different instance.
+ */
+
+/*
+ * Variable: oWin
+ * Purpose: Store information about the window positioning
+ * Scope: FixedHeader
+ */
+FixedHeader.oWin = {
+ "iScrollTop": 0,
+ "iScrollRight": 0,
+ "iScrollBottom": 0,
+ "iScrollLeft": 0,
+ "iHeight": 0,
+ "iWidth": 0
+};
+
+/*
+ * Variable: oDoc
+ * Purpose: Store information about the document size
+ * Scope: FixedHeader
+ */
+FixedHeader.oDoc = {
+ "iHeight": 0,
+ "iWidth": 0
+};
+
+/*
+ * Variable: afnScroll
+ * Purpose: Array of functions that are to be used for the scrolling components
+ * Scope: FixedHeader
+ */
+FixedHeader.afnScroll = [];
+
+/*
+ * Function: fnMeasure
+ * Purpose: Update the measurements for the window and document
+ * Returns: -
+ * Inputs: -
+ */
+FixedHeader.fnMeasure = function ()
+{
+ var
+ jqWin = jQuery(window),
+ jqDoc = jQuery(document),
+ oWin = FixedHeader.oWin,
+ oDoc = FixedHeader.oDoc;
+
+ oDoc.iHeight = jqDoc.height();
+ oDoc.iWidth = jqDoc.width();
+
+ oWin.iHeight = jqWin.height();
+ oWin.iWidth = jqWin.width();
+ oWin.iScrollTop = jqWin.scrollTop();
+ oWin.iScrollLeft = jqWin.scrollLeft();
+ oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth;
+ oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight;
+};
+
+
+FixedHeader.VERSION = "2.0.6";
+FixedHeader.prototype.VERSION = FixedHeader.VERSION;
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Global processing
+ */
+
+/*
+ * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is
+ * done as an optimisation, to reduce calculation and proagation time
+ */
+jQuery(window).scroll( function () {
+ FixedHeader.fnMeasure();
+ for ( var i=0, iLen=FixedHeader.afnScroll.length ; itfoot",b.nTable).length?!0:!1;b.bUseAbsPos=jQuery.browser.msie&&("6.0"==jQuery.browser.version||"7.0"==jQuery.browser.version);b.oSides.top&&b.aoCache.push(d._fnCloneTable("fixedHeader","FixedHeader_Header",d._fnCloneThead));b.oSides.bottom&&b.aoCache.push(d._fnCloneTable("fixedFooter","FixedHeader_Footer",d._fnCloneTfoot));b.oSides.left&&b.aoCache.push(d._fnCloneTable("fixedLeft","FixedHeader_Left",
+d._fnCloneTLeft));b.oSides.right&&b.aoCache.push(d._fnCloneTable("fixedRight","FixedHeader_Right",d._fnCloneTRight));FixedHeader.afnScroll.push(function(){d._fnUpdatePositions.call(d)});jQuery(window).resize(function(){FixedHeader.fnMeasure();d._fnUpdateClones.call(d);d._fnUpdatePositions.call(d)});FixedHeader.fnMeasure();d._fnUpdateClones();d._fnUpdatePositions()},fnInitSettings:function(a,c){if("undefined"!=typeof c&&("undefined"!=typeof c.top&&(a.oSides.top=c.top),"undefined"!=typeof c.bottom&&
+(a.oSides.bottom=c.bottom),"undefined"!=typeof c.left&&(a.oSides.left=c.left),"undefined"!=typeof c.right&&(a.oSides.right=c.right),"undefined"!=typeof c.zTop&&(a.oZIndexes.top=c.zTop),"undefined"!=typeof c.zBottom&&(a.oZIndexes.bottom=c.zBottom),"undefined"!=typeof c.zLeft&&(a.oZIndexes.left=c.zLeft),"undefined"!=typeof c.zRight&&(a.oZIndexes.right=c.zRight),"undefined"!=typeof c.offsetTop))a.oOffset.top=c.offsetTop;a.bUseAbsPos=jQuery.browser.msie&&("6.0"==jQuery.browser.version||"7.0"==jQuery.browser.version)},
+_fnCloneTable:function(a,c,b){var d=this.fnGetSettings(),e;"absolute"!=jQuery(d.nTable.parentNode).css("position")&&(d.nTable.parentNode.style.position="relative");e=d.nTable.cloneNode(!1);e.removeAttribute("id");var f=document.createElement("div");f.style.position="absolute";f.style.top="0px";f.style.left="0px";f.className+=" FixedHeader_Cloned "+a+" "+c;"fixedHeader"==a&&(f.style.zIndex=d.oZIndexes.top);"fixedFooter"==a&&(f.style.zIndex=d.oZIndexes.bottom);"fixedLeft"==a?f.style.zIndex=d.oZIndexes.left:
+"fixedRight"==a&&(f.style.zIndex=d.oZIndexes.right);e.style.margin="0";f.appendChild(e);document.body.appendChild(f);return{nNode:e,nWrapper:f,sType:a,sPosition:"",sTop:"",sLeft:"",fnClone:b}},_fnMeasure:function(){var a=this.fnGetSettings(),c=a.oMes,b=jQuery(a.nTable),d=b.offset(),e=this._fnSumScroll(a.nTable.parentNode,"scrollTop");this._fnSumScroll(a.nTable.parentNode,"scrollLeft");c.iTableWidth=b.outerWidth();c.iTableHeight=b.outerHeight();c.iTableLeft=d.left+a.nTable.parentNode.scrollLeft;c.iTableTop=
+d.top+e;c.iTableRight=c.iTableLeft+c.iTableWidth;c.iTableRight=FixedHeader.oDoc.iWidth-c.iTableLeft-c.iTableWidth;c.iTableBottom=FixedHeader.oDoc.iHeight-c.iTableTop-c.iTableHeight},_fnSumScroll:function(a,c){for(var b=a[c];(a=a.parentNode)&&!("HTML"==a.nodeName||"BODY"==a.nodeName);)b=a[c];return b},_fnUpdatePositions:function(){var a=this.fnGetSettings();this._fnMeasure();for(var c=0,b=a.aoCache.length;cd.iScrollTop+c.oOffset.top?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",e.style)):d.iScrollTop+c.oOffset.top>b.iTableTop+f?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",b.iTableTop+f+"px","top",e.style),this._fnUpdateCache(a,
+"sLeft",b.iTableLeft+"px","left",e.style)):c.bUseAbsPos?(this._fnUpdateCache(a,"sPosition","absolute","position",e.style),this._fnUpdateCache(a,"sTop",d.iScrollTop+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft+"px","left",e.style)):(this._fnUpdateCache(a,"sPosition","fixed","position",e.style),this._fnUpdateCache(a,"sTop",c.oOffset.top+"px","top",e.style),this._fnUpdateCache(a,"sLeft",b.iTableLeft-d.iScrollLeft+"px","left",e.style))},_fnUpdateCache:function(a,c,b,d,e){a[c]!=b&&(e[d]=
+b,a[c]=b)},_fnCloneThead:function(a){var c=this.fnGetSettings(),b=a.nNode;for(a.nWrapper.style.width=jQuery(c.nTable).outerWidth()+"px";0tr th",c.nTable).each(function(a){jQuery("thead>tr th:eq("+a+")",b).width(jQuery(this).width())});jQuery("thead>tr td",c.nTable).each(function(a){jQuery("thead>tr td:eq("+a+")",b).width(jQuery(this).width())})},
+_fnCloneTfoot:function(a){var c=this.fnGetSettings(),b=a.nNode;for(a.nWrapper.style.width=jQuery(c.nTable).outerWidth()+"px";0tr th",c.nTable).each(function(a){jQuery("tfoot:eq(0)>tr th:eq("+a+")",b).width(jQuery(this).width())});jQuery("tfoot:eq(0)>tr td",c.nTable).each(function(a){jQuery("tfoot:eq(0)>tr th:eq("+a+")",b)[0].style.width(jQuery(this).width())})},_fnCloneTLeft:function(a){var c=
+this.fnGetSettings(),b=a.nNode,d=$("tbody",c.nTable)[0];for($("tbody tr:eq(0) td",c.nTable);0 */function($, window, document, undefined) {
/**
@@ -76,7 +76,7 @@
"nTh": nTh ? nTh : document.createElement('th'),
"sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
- "mDataProp": oDefaults.mDataProp ? oDefaults.oDefaults : iCol
+ "mData": oDefaults.mData ? oDefaults.oDefaults : iCol
} );
oSettings.aoColumns.push( oCol );
@@ -115,7 +115,7 @@
* Apply options for a column
* @param {object} oSettings dataTables settings object
* @param {int} iCol column index to consider
- * @param {object} oOptions object with sType, bVisible and bSearchable
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
* @memberof DataTable#oApi
*/
function _fnColumnOptions( oSettings, iCol, oOptions )
@@ -125,6 +125,12 @@
/* User specified column options */
if ( oOptions !== undefined && oOptions !== null )
{
+ /* Backwards compatibility for mDataProp */
+ if ( oOptions.mDataProp && !oOptions.mData )
+ {
+ oOptions.mData = oOptions.mDataProp;
+ }
+
if ( oOptions.sType !== undefined )
{
oCol.sType = oOptions.sType;
@@ -145,8 +151,19 @@
}
/* Cache the data get and set functions for speed */
- oCol.fnGetData = _fnGetObjectDataFn( oCol.mDataProp );
- oCol.fnSetData = _fnSetObjectDataFn( oCol.mDataProp );
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
+ var mData = _fnGetObjectDataFn( oCol.mData );
+
+ oCol.fnGetData = function (oData, sSpecific) {
+ var innerData = mData( oData, sSpecific );
+
+ if ( oCol.mRender && (sSpecific && sSpecific !== '') )
+ {
+ return mRender( innerData, sSpecific, oData );
+ }
+ return innerData;
+ };
+ oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
/* Feature sorting overrides column specific when off */
if ( !oSettings.oFeatures.bSort )
@@ -188,7 +205,7 @@
*/
function _fnAdjustColumnSizing ( oSettings )
{
- /* Not interested in doing column width calculation if autowidth is disabled */
+ /* Not interested in doing column width calculation if auto-width is disabled */
if ( oSettings.oFeatures.bAutoWidth === false )
{
return false;
@@ -212,22 +229,11 @@
*/
function _fnVisibleToColumnIndex( oSettings, iMatch )
{
- var iColumn = -1;
-
- for ( var i=0 ; i tag - remove it */
- sSearch = sSearch.replace(/\n/g," ").replace(/\r/g,"");
+ sSearch = $('
').html(sSearch).text();
}
- return sSearch;
+ // Strip newline characters
+ return sSearch.replace( /[\n\r]/g, " " );
}
/**
@@ -2259,7 +2363,7 @@
* @param {string} sSearch string to search for
* @param {bool} bRegex treat as a regular expression or not
* @param {bool} bSmart perform smart filtering or not
- * @param {bool} bCaseInsensitive Do case insenstive matching or not
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
* @returns {RegExp} constructed object
* @memberof DataTable#oApi
*/
@@ -2297,6 +2401,10 @@
{
return DataTable.ext.ofnSearch[sType]( sData );
}
+ else if ( sData === null )
+ {
+ return '';
+ }
else if ( sType == "html" )
{
return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
@@ -2305,23 +2413,19 @@
{
return sData.replace(/[\r\n]/g," ");
}
- else if ( sData === null )
- {
- return '';
- }
return sData;
}
/**
- * scape a string stuch that it can be used in a regular expression
+ * scape a string such that it can be used in a regular expression
* @param {string} sVal string to escape
* @returns {string} escaped string
* @memberof DataTable#oApi
*/
function _fnEscapeRegex ( sVal )
{
- var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^' ];
+ var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];
var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
return sVal.replace(reReplace, '\\$1');
}
@@ -2371,57 +2475,41 @@
}
var
- iStart = oSettings._iDisplayStart+1, iEnd = oSettings.fnDisplayEnd(),
- iMax = oSettings.fnRecordsTotal(), iTotal = oSettings.fnRecordsDisplay(),
- sStart = oSettings.fnFormatNumber( iStart ), sEnd = oSettings.fnFormatNumber( iEnd ),
- sMax = oSettings.fnFormatNumber( iMax ), sTotal = oSettings.fnFormatNumber( iTotal ),
+ oLang = oSettings.oLanguage,
+ iStart = oSettings._iDisplayStart+1,
+ iEnd = oSettings.fnDisplayEnd(),
+ iMax = oSettings.fnRecordsTotal(),
+ iTotal = oSettings.fnRecordsDisplay(),
sOut;
- /* When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
- * internally
- */
- if ( oSettings.oScroll.bInfinite )
- {
- sStart = oSettings.fnFormatNumber( 1 );
- }
-
- if ( oSettings.fnRecordsDisplay() === 0 &&
- oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
+ if ( iTotal === 0 && iTotal == iMax )
{
/* Empty record set */
- sOut = oSettings.oLanguage.sInfoEmpty+ oSettings.oLanguage.sInfoPostFix;
+ sOut = oLang.sInfoEmpty;
}
- else if ( oSettings.fnRecordsDisplay() === 0 )
+ else if ( iTotal === 0 )
{
- /* Rmpty record set after filtering */
- sOut = oSettings.oLanguage.sInfoEmpty +' '+
- oSettings.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+
- oSettings.oLanguage.sInfoPostFix;
+ /* Empty record set after filtering */
+ sOut = oLang.sInfoEmpty +' '+ oLang.sInfoFiltered;
}
- else if ( oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
+ else if ( iTotal == iMax )
{
/* Normal record set */
- sOut = oSettings.oLanguage.sInfo.
- replace('_START_', sStart).
- replace('_END_', sEnd).
- replace('_TOTAL_', sTotal)+
- oSettings.oLanguage.sInfoPostFix;
+ sOut = oLang.sInfo;
}
else
{
/* Record set after filtering */
- sOut = oSettings.oLanguage.sInfo.
- replace('_START_', sStart).
- replace('_END_', sEnd).
- replace('_TOTAL_', sTotal) +' '+
- oSettings.oLanguage.sInfoFiltered.replace('_MAX_',
- oSettings.fnFormatNumber(oSettings.fnRecordsTotal()))+
- oSettings.oLanguage.sInfoPostFix;
+ sOut = oLang.sInfo +' '+ oLang.sInfoFiltered;
}
+
+ // Convert the macros
+ sOut += oLang.sInfoPostFix;
+ sOut = _fnInfoMacros( oSettings, sOut );
- if ( oSettings.oLanguage.fnInfoCallback !== null )
+ if ( oLang.fnInfoCallback !== null )
{
- sOut = oSettings.oLanguage.fnInfoCallback.call( oSettings.oInstance,
+ sOut = oLang.fnInfoCallback.call( oSettings.oInstance,
oSettings, iStart, iEnd, iMax, iTotal, sOut );
}
@@ -2433,6 +2521,33 @@
}
+ function _fnInfoMacros ( oSettings, str )
+ {
+ var
+ iStart = oSettings._iDisplayStart+1,
+ sStart = oSettings.fnFormatNumber( iStart ),
+ iEnd = oSettings.fnDisplayEnd(),
+ sEnd = oSettings.fnFormatNumber( iEnd ),
+ iTotal = oSettings.fnRecordsDisplay(),
+ sTotal = oSettings.fnFormatNumber( iTotal ),
+ iMax = oSettings.fnRecordsTotal(),
+ sMax = oSettings.fnFormatNumber( iMax );
+
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+ // internally
+ if ( oSettings.oScroll.bInfinite )
+ {
+ sStart = oSettings.fnFormatNumber( 1 );
+ }
+
+ return str.
+ replace('_START_', sStart).
+ replace('_END_', sEnd).
+ replace('_TOTAL_', sTotal).
+ replace('_MAX_', sMax);
+ }
+
+
/**
* Draw the table for the first time, adding all required features
@@ -2566,16 +2681,20 @@
*/
function _fnLanguageCompat( oLanguage )
{
+ var oDefaults = DataTable.defaults.oLanguage;
+
/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
* sZeroRecords - assuming that is given.
*/
- if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords )
+ if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&
+ oDefaults.sEmptyTable === "No data available in table" )
{
_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
}
/* Likewise with loading records */
- if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords )
+ if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&
+ oDefaults.sLoadingRecords === "Loading..." )
{
_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
}
@@ -2676,7 +2795,7 @@
/**
- * Rcalculate the end point based on the start point
+ * Recalculate the end point based on the start point
* @param {object} oSettings dataTables settings object
* @memberof DataTable#oApi
*/
@@ -2780,7 +2899,7 @@
oSettings._iDisplayStart - oSettings._iDisplayLength :
0;
- /* Correct for underrun */
+ /* Correct for under-run */
if ( oSettings._iDisplayStart < 0 )
{
oSettings._iDisplayStart = 0;
@@ -2944,7 +3063,8 @@
nScrollHead.style.border = "0";
nScrollHead.style.width = "100%";
nScrollFoot.style.border = "0";
- nScrollHeadInner.style.width = "150%"; /* will be overwritten */
+ nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ?
+ oSettings.oScroll.sXInner : "100%"; /* will be overwritten */
/* Modify attributes to respect the clones */
nScrollHeadTable.removeAttribute('id');
@@ -2956,17 +3076,26 @@
nScrollFootTable.style.marginLeft = "0";
}
- /* Move any caption elements from the body to the header */
- var nCaptions = $(oSettings.nTable).children('caption');
- for ( var i=0, iLen=nCaptions.length ; i 0 )
{
- nScrollHeadTable.appendChild( nCaptions[i] );
+ nCaption = nCaption[0];
+ if ( nCaption._captionSide === "top" )
+ {
+ nScrollHeadTable.appendChild( nCaption );
+ }
+ else if ( nCaption._captionSide === "bottom" && nTfoot )
+ {
+ nScrollFootTable.appendChild( nCaption );
+ }
}
/*
* Sizing
*/
- /* When xscrolling add the width and a scroller to move the header with the body */
+ /* When x-scrolling add the width and a scroller to move the header with the body */
if ( oSettings.oScroll.sX !== "" )
{
nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
@@ -3048,40 +3177,26 @@
nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
nScrollBody = o.nTable.parentNode,
i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
+ nTheadSize, nTfootSize,
iWidth, aApplied=[], iSanityWidth,
nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
- ie67 = $.browser.msie && $.browser.version <= 7;
+ ie67 = o.oBrowser.bScrollOversize;
/*
* 1. Re-create the table inside the scrolling div
*/
/* Remove the old minimised thead and tfoot elements in the inner table */
- var nTheadSize = o.nTable.getElementsByTagName('thead');
- if ( nTheadSize.length > 0 )
- {
- o.nTable.removeChild( nTheadSize[0] );
- }
-
- var nTfootSize;
- if ( o.nTFoot !== null )
- {
- /* Remove the old minimised footer element in the cloned header */
- nTfootSize = o.nTable.getElementsByTagName('tfoot');
- if ( nTfootSize.length > 0 )
- {
- o.nTable.removeChild( nTfootSize[0] );
- }
- }
-
+ $(o.nTable).children('thead, tfoot').remove();
+
/* Clone the current header and footer elements and then place it into the inner table */
- nTheadSize = o.nTHead.cloneNode(true);
+ nTheadSize = $(o.nTHead).clone()[0];
o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
if ( o.nTFoot !== null )
{
- nTfootSize = o.nTFoot.cloneNode(true);
+ nTfootSize = $(o.nTFoot).clone()[0];
o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
}
@@ -3091,7 +3206,7 @@
/* Remove old sizing and apply the calculated column widths
* Get the unique column headers in the newly created (cloned) header. We want to apply the
- * calclated sizes to this header
+ * calculated sizes to this header
*/
if ( o.oScroll.sX === "" )
{
@@ -3112,6 +3227,14 @@
n.style.width = "";
}, nTfootSize.getElementsByTagName('tr') );
}
+
+ // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
+ // will end up forcing the scrollbar to appear, making our measurements wrong for when we
+ // then hide it (end of this function), so add the header height to the body scroller.
+ if ( o.oScroll.bCollapse && o.oScroll.sY !== "" )
+ {
+ nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";
+ }
/* Size the table as a whole */
iSanityWidth = $(o.nTable).outerWidth();
@@ -3127,7 +3250,7 @@
if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight ||
$(nScrollBody).css('overflow-y') == "scroll") )
{
- o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth()-o.oScroll.iBarWidth );
+ o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
}
}
else
@@ -3296,7 +3419,7 @@
o.oScroll.iBarWidth : 0;
if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
{
- nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );
+ nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
}
}
@@ -3304,12 +3427,21 @@
var iOuterWidth = $(o.nTable).outerWidth();
nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
+
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
+ var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll";
+ nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
if ( o.nTFoot !== null )
{
- nScrollFootInner.style.width = _fnStringToCss( o.nTable.offsetWidth );
- nScrollFootTable.style.width = _fnStringToCss( o.nTable.offsetWidth );
+ nScrollFootTable.style.width = _fnStringToCss( iOuterWidth );
+ nScrollFootInner.style.width = _fnStringToCss( iOuterWidth );
+ nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
}
+
+ /* Adjust the position of the header in case we loose the y-scrollbar */
+ $(nScrollBody).scroll();
/* If sorting or filtering has occurred, jump the scrolling back to the top */
if ( o.bSorted || o.bFiltered )
@@ -3634,7 +3766,7 @@
* Get the widest node
* @param {object} oSettings dataTables settings object
* @param {int} iCol column of interest
- * @returns {string} max strlens for each column
+ * @returns {string} max string length for each column
* @memberof DataTable#oApi
*/
function _fnGetWidestNode( oSettings, iCol )
@@ -3659,7 +3791,7 @@
* Get the maximum strlen for each data column
* @param {object} oSettings dataTables settings object
* @param {int} iCol column of interest
- * @returns {string} max strlens for each column
+ * @returns {string} max string length for each column
* @memberof DataTable#oApi
*/
function _fnGetMaxLenString( oSettings, iCol )
@@ -3777,16 +3909,11 @@
if ( !oSettings.oFeatures.bServerSide &&
(oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
{
- if ( oSettings.aaSortingFixed !== null )
- {
- aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
- }
- else
- {
- aaSort = oSettings.aaSorting.slice();
- }
+ aaSort = ( oSettings.aaSortingFixed !== null ) ?
+ oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
+ oSettings.aaSorting.slice();
- /* If there is a sorting data type, and a fuction belonging to it, then we need to
+ /* If there is a sorting data type, and a function belonging to it, then we need to
* get the data from the developer's function and apply it for this column
*/
for ( i=0 ; i/g, "" );
nTh = aoColumns[i].nTh;
nTh.removeAttribute('aria-sort');
nTh.removeAttribute('aria-label');
@@ -3900,18 +4037,18 @@
var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ?
aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
- nTh.setAttribute('aria-label', aoColumns[i].sTitle+
+ nTh.setAttribute('aria-label', sTitle+
(nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
}
else
{
- nTh.setAttribute('aria-label', aoColumns[i].sTitle+
+ nTh.setAttribute('aria-label', sTitle+
(aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
}
}
else
{
- nTh.setAttribute('aria-label', aoColumns[i].sTitle);
+ nTh.setAttribute('aria-label', sTitle);
}
}
@@ -3958,17 +4095,17 @@
* twice - once for when bProcessing is enabled, and another time for when it is
* disabled, as we need to perform slightly different actions.
* Basically the issue here is that the Javascript engine in modern browsers don't
- * appear to allow the rendering engine to update the display while it is still excuting
+ * appear to allow the rendering engine to update the display while it is still executing
* it's thread (well - it does but only after long intervals). This means that the
* 'processing' display doesn't appear for a table sort. To break the js thread up a bit
* I force an execution break by using setTimeout - but this breaks the expected
* thread continuation for the end-developer's point of view (their code would execute
- * too early), so we on;y do it when we absolutely have to.
+ * too early), so we only do it when we absolutely have to.
*/
var fnInnerSorting = function () {
var iColumn, iNextSort;
- /* If the shift key is pressed then we are multipe column sorting */
+ /* If the shift key is pressed then we are multiple column sorting */
if ( e.shiftKey )
{
/* Are we already doing some kind of sort on this column? */
@@ -4141,10 +4278,10 @@
* Apply the required classes to the table body
* Note that this is given as a feature switch since it can significantly slow down a sort
* on large data sets (adding and removing of classes is always slow at the best of times..)
- * Further to this, note that this code is admitadly fairly ugly. It could be made a lot
- * simpiler using jQuery selectors and add/removeClass, but that is significantly slower
+ * Further to this, note that this code is admittedly fairly ugly. It could be made a lot
+ * simpler using jQuery selectors and add/removeClass, but that is significantly slower
* (on the order of 5 times slower) - hence the direct DOM manipulation here.
- * Note that for defered drawing we do use jQuery - the reason being that taking the first
+ * Note that for deferred drawing we do use jQuery - the reason being that taking the first
* row found to see if the whole column needs processed can miss classes since the first
* column might be new.
*/
@@ -4290,7 +4427,7 @@
$.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
/* Column visibility state
- * Pass back visibiliy settings to the init handler, but to do not here override
+ * Pass back visibility settings to the init handler, but to do not here override
* the init object that the user might have passed in
*/
oInit.saved_aoColumns = [];
@@ -4532,11 +4669,11 @@
}
else
{
- throw sAlert;
+ throw new Error(sAlert);
}
return;
}
- else if ( console !== undefined && console.log )
+ else if ( window.console && console.log )
{
console.log( sAlert );
}
@@ -4577,17 +4714,21 @@
*/
function _fnExtend( oOut, oExtender )
{
- for ( var prop in oOut )
+ var val;
+
+ for ( var prop in oExtender )
{
- if ( oOut.hasOwnProperty(prop) && oExtender[prop] !== undefined )
+ if ( oExtender.hasOwnProperty(prop) )
{
- if ( typeof oInit[prop] === 'object' && $.isArray(oExtender[prop]) === false )
+ val = oExtender[prop];
+
+ if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
{
- $.extend( true, oOut[prop], oExtender[prop] );
+ $.extend( true, oOut[prop], val );
}
else
{
- oOut[prop] = oExtender[prop];
+ oOut[prop] = val;
}
}
}
@@ -4598,19 +4739,19 @@
/**
* Bind an event handers to allow a click or return key to activate the callback.
- * This is good for accessability since a return on the keyboard will have the
+ * This is good for accessibility since a return on the keyboard will have the
* same effect as a click, if the element has focus.
* @param {element} n Element to bind the action to
* @param {object} oData Data object to pass to the triggered function
- * @param {function) fn Callback function for when the event is triggered
+ * @param {function} fn Callback function for when the event is triggered
* @memberof DataTable#oApi
*/
function _fnBindAction( n, oData, fn )
{
$(n)
.bind( 'click.DT', oData, function (e) {
- fn(e);
n.blur(); // Remove focus outline for mouse users
+ fn(e);
} )
.bind( 'keypress.DT', oData, function (e){
if ( e.which === 13 ) {
@@ -4627,9 +4768,9 @@
* Register a callback function. Easily allows a callback function to be added to
* an array store of callback functions that can then all be called together.
* @param {object} oSettings dataTables settings object
- * @param {string} sStore Name of the array storeage for the callbacks in oSettings
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
* @param {function} fn Function to be called back
- * @param {string) sName Identifying name for the callback (i.e. a label)
+ * @param {string} sName Identifying name for the callback (i.e. a label)
* @memberof DataTable#oApi
*/
function _fnCallbackReg( oSettings, sStore, fn, sName )
@@ -4649,10 +4790,10 @@
* array store is done backwards! Further note that you do not want to fire off triggers
* in time sensitive applications (for example cell creation) as its slow.
* @param {object} oSettings dataTables settings object
- * @param {string} sStore Name of the array storeage for the callbacks in oSettings
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
* @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
* is fired
- * @param {array) aArgs Array of arguments to pass to the callback function / trigger
+ * @param {array} aArgs Array of arguments to pass to the callback function / trigger
* @memberof DataTable#oApi
*/
function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
@@ -4677,7 +4818,7 @@
/**
* JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
* library, then we use that as it is fast, safe and accurate. If the function isn't
- * available then we need to built it ourselves - the insperation for this function comes
+ * available then we need to built it ourselves - the inspiration for this function comes
* from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
* not perfect and absolutely should not be used as a replacement to json2.js - but it does
* do what we need, without requiring a dependency for DataTables.
@@ -4725,6 +4866,31 @@
return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
};
+
+ /**
+ * From some browsers (specifically IE6/7) we need special handling to work around browser
+ * bugs - this function is used to detect when these workarounds are needed.
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnBrowserDetect( oSettings )
+ {
+ /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
+ * width of the scrollbar, while other browsers ensure the inner element is contained
+ * without forcing scrolling
+ */
+ var n = $(
+ '
'+
+ '
'+
+ ''+
+ '
'+
+ '
')[0];
+
+ document.body.appendChild( n );
+ oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
+ document.body.removeChild( n );
+ }
+
@@ -4765,8 +4931,11 @@
*/
this.$ = function ( sSelector, oOpts )
{
- var i, iLen, a = [];
+ var i, iLen, a = [], tr;
var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+ var aoData = oSettings.aoData;
+ var aiDisplay = oSettings.aiDisplay;
+ var aiDisplayMaster = oSettings.aiDisplayMaster;
if ( !oOpts )
{
@@ -4785,37 +4954,54 @@
{
for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i
*
1D array of data - add a single row with the data provided
*
2D array of arrays - add multiple rows in a single call
- *
object - data object when using mDataProp
- *
array of objects - multiple data objects when using mDataProp
+ *
object - data object when using mData
+ *
array of objects - multiple data objects when using mData
*
* @param {bool} [bRedraw=true] redraw the table or not
* @returns {array} An array of integers, representing the list of indexes in
@@ -5142,8 +5328,8 @@
fnCallBack.call( this, oSettings, oData );
}
- /* Check for an 'overflow' they case for dislaying the table */
- if ( oSettings._iDisplayStart >= oSettings.aiDisplay.length )
+ /* Check for an 'overflow' they case for displaying the table */
+ if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
{
oSettings._iDisplayStart -= oSettings._iDisplayLength;
if ( oSettings._iDisplayStart < 0 )
@@ -5187,10 +5373,8 @@
/* Flag to note that the table is currently being destroyed - no action should be taken */
oSettings.bDestroying = true;
- /* Restore hidden columns */
- for ( i=0, iLen=oSettings.aoDestroyCallback.length ; i 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
+ {
+ // If we are a scrolling table, and no footer has been given, then we need to create
+ // a tfoot element for the caption element to be appended to
+ tfoot = [ document.createElement( 'tfoot' ) ];
+ this.appendChild( tfoot[0] );
+ }
+
if ( tfoot.length > 0 )
{
oSettings.nTFoot = tfoot[0];
@@ -6534,41 +6744,140 @@
} );
};
- /**
- * Version string for plug-ins to check compatibility. Allowed format is
- * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
- * e are optional
- * @member
- * @type string
- * @default Version number
- */
- DataTable.version = "1.9.0";
-
- /**
- * Private data store, containing all of the settings objects that are created for the
- * tables on a given page.
- *
- * Note that the DataTable.settings object is aliased to jQuery.fn.dataTableExt
- * through which it may be accessed and manipulated, or jQuery.fn.dataTable.settings.
- * @member
- * @type array
- * @default []
- * @private
- */
- DataTable.settings = [];
-
- /**
- * Object models container, for the various models that DataTables has available
- * to it. These models define the objects that are used to hold the active state
- * and configuration of the table.
- * @namespace
- */
- DataTable.models = {};
/**
- * DataTables extension options and plug-ins. This namespace acts as a collection "area"
- * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
+ * to ensure compatibility.
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+ * formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
+ * version, or false if this version of DataTales is not suitable
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
+ */
+ DataTable.fnVersionCheck = function( sVersion )
+ {
+ /* This is cheap, but effective */
+ var fnZPad = function (Zpad, count)
+ {
+ while(Zpad.length < count) {
+ Zpad += '0';
+ }
+ return Zpad;
+ };
+ var aThis = DataTable.ext.sVersion.split('.');
+ var aThat = sVersion.split('.');
+ var sThis = '', sThat = '';
+
+ for ( var i=0, iLen=aThat.length ; i= parseInt(sThat, 10);
+ };
+
+
+ /**
+ * Check if a TABLE node is a DataTable table already or not.
+ * @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
+ * node types can be passed in, but will always return false).
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * var ex = document.getElementById('example');
+ * if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
+ * $(ex).dataTable();
+ * }
+ */
+ DataTable.fnIsDataTable = function ( nTable )
+ {
+ var o = DataTable.settings;
+
+ for ( var i=0 ; i 0 ) {
+ * $(table).dataTable().fnAdjustColumnSizing();
+ * }
+ */
+ DataTable.fnTables = function ( bVisible )
+ {
+ var out = [];
+
+ jQuery.each( DataTable.settings, function (i, o) {
+ if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
+ {
+ out.push( o.nTable );
+ }
+ } );
+
+ return out;
+ };
+
+
+ /**
+ * Version string for plug-ins to check compatibility. Allowed format is
+ * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
+ * e are optional
+ * @member
+ * @type string
+ * @default Version number
+ */
+ DataTable.version = "1.9.3";
+
+ /**
+ * Private data store, containing all of the settings objects that are created for the
+ * tables on a given page.
+ *
+ * Note that the DataTable.settings object is aliased to jQuery.fn.dataTableExt
+ * through which it may be accessed and manipulated, or jQuery.fn.dataTable.settings.
+ * @member
+ * @type array
+ * @default []
+ * @private
+ */
+ DataTable.settings = [];
+
+ /**
+ * Object models container, for the various models that DataTables has available
+ * to it. These models define the objects that are used to hold the active state
+ * and configuration of the table.
+ * @namespace
+ */
+ DataTable.models = {};
+
+
+ /**
+ * DataTables extension options and plug-ins. This namespace acts as a collection "area"
+ * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
* of the build in methods use this method to provide their own capabilities (sorting methods
* for example).
*
@@ -6658,8 +6967,8 @@
*
*
*
- * Note that as of v1.9, it is typically preferable to use mDataProp to prepare data for
- * the different uses that DataTables can put the data to. Specifically mDataProp when
+ * Note that as of v1.9, it is typically preferable to use mData to prepare data for
+ * the different uses that DataTables can put the data to. Specifically mData when
* used as a function will give you a 'type' (sorting, filtering etc) that you can use to
* prepare the data as required for the different types. As such, this method is deprecated.
* @type array
@@ -6790,28 +7099,7 @@
* alert( oTable.fnVersionCheck( '1.9.0' ) );
* } );
*/
- "fnVersionCheck": function( sVersion )
- {
- /* This is cheap, but very effective */
- var fnZPad = function (Zpad, count)
- {
- while(Zpad.length < count) {
- Zpad += '0';
- }
- return Zpad;
- };
- var aThis = DataTable.ext.sVersion.split('.');
- var aThat = sVersion.split('.');
- var sThis = '', sThat = '';
-
- for ( var i=0, iLen=aThat.length ; i= parseInt(sThat, 10);
- },
+ "fnVersionCheck": DataTable.fnVersionCheck,
/**
@@ -6845,8 +7133,8 @@
*
*
*
- * Note that as of v1.9, it is typically preferable to use mDataProp to prepare data for
- * the different uses that DataTables can put the data to. Specifically mDataProp when
+ * Note that as of v1.9, it is typically preferable to use mData to prepare data for
+ * the different uses that DataTables can put the data to. Specifically mData when
* used as a function will give you a 'type' (sorting, filtering etc) that you can use to
* prepare the data as required for the different types. As such, this method is deprecated.
* @type object
@@ -7173,7 +7461,7 @@
/**
* Data object from the original data source for the row. This is either
* an array if using the traditional form of DataTables, or an object if
- * using mDataProp options. The exact type will depend on the passed in
+ * using mData options. The exact type will depend on the passed in
* data from the data source, or will be an array if using DOM a data
* source.
* @type array|object
@@ -7272,7 +7560,7 @@
* and filtering use the rendered value (true - default), or you can have
* the sorting and filtering us the original value (false).
*
- * *NOTE* It is it is advisable now to use mDataProp as a function and make
+ * *NOTE* It is it is advisable now to use mData as a function and make
* use of the 'type' that it gives, allowing (potentially) different data to
* be used for sorting, filtering, display and type detection.
* @type boolean
@@ -7312,7 +7600,7 @@
/**
* Function to get data from a cell in a column. You should never
* access data directly through _aData internally in DataTables - always use
- * the method attached to this property. It allows mDataProp to function as
+ * the method attached to this property. It allows mData to function as
* required. This function is automatically assigned by the column
* initialisation method
* @type function
@@ -7332,7 +7620,7 @@
* @param {object} o Object with the following parameters:
* @param {int} o.iDataRow The row in aoData
* @param {int} o.iDataColumn The column in question
- * @param {array o.aData The data for the row in question
+ * @param {array} o.aData The data for the row in question
* @param {object} o.oSettings The settings object for this DataTables instance
* @returns {string} The string you which to use in the display
* @default null
@@ -7342,7 +7630,7 @@
/**
* Function to set data for a cell in the column. You should never
* set the data directly to _aData internally in DataTables - always use
- * this method. It allows mDataProp to function as required. This function
+ * this method. It allows mData to function as required. This function
* is automatically assigned by the column initialisation method
* @type function
* @param {array|object} oData The data array/object for the array
@@ -7359,7 +7647,17 @@
* @type function|int|string|null
* @default null
*/
- "mDataProp": null,
+ "mData": null,
+
+ /**
+ * Partner property to mData which is used (only when defined) to get
+ * the data - i.e. it is basically the same as mData, but without the
+ * 'set' option, and also the data fed to it is the result from mData.
+ * This is the rendering method to match the data method of mData.
+ * @type function|int|string|null
+ * @default null
+ */
+ "mRender": null,
/**
* Unique header TH/TD element for this column - this is what the sorting
@@ -7400,7 +7698,7 @@
/**
* Allows a default value to be given for a column's data, and will be used
- * whenever a null data source is encountered (this can be because mDataProp
+ * whenever a null data source is encountered (this can be because mData
* is set to null, or because the data source itself is null).
* @type string
* @default null
@@ -7501,7 +7799,7 @@
* } );
*
* @example
- * // Using an array of objects as a data source (mDataProp)
+ * // Using an array of objects as a data source (mData)
* $(document).ready( function () {
* $('#example').dataTable( {
* "aaData": [
@@ -7521,11 +7819,11 @@
* }
* ],
* "aoColumns": [
- * { "sTitle": "Engine", "mDataProp": "engine" },
- * { "sTitle": "Browser", "mDataProp": "browser" },
- * { "sTitle": "Platform", "mDataProp": "platform" },
- * { "sTitle": "Version", "mDataProp": "version" },
- * { "sTitle": "Grade", "mDataProp": "grade" }
+ * { "sTitle": "Engine", "mData": "engine" },
+ * { "sTitle": "Browser", "mData": "browser" },
+ * { "sTitle": "Platform", "mData": "platform" },
+ * { "sTitle": "Version", "mData": "version" },
+ * { "sTitle": "Grade", "mData": "grade" }
* ]
* } );
* } );
@@ -7594,7 +7892,7 @@
* @dtopt Option
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
* } );
@@ -7604,7 +7902,7 @@
* // Setting the default display length as well as length menu
* // This is likely to be wanted if you remove the '10' option which
* // is the iDisplayLength default.
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "iDisplayLength": 25,
* "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
@@ -7676,7 +7974,8 @@
* array may be of any length, and DataTables will apply each class
* sequentially, looping when required.
* @type array
- * @default [ 'odd', 'even' ]
+ * @default null Will take the values determined by the oClasses.sStripe*
+ * options
* @dtopt Option
*
* @example
@@ -7686,7 +7985,7 @@
* } );
* } )
*/
- "asStripeClasses": [ 'odd', 'even' ],
+ "asStripeClasses": null,
/**
@@ -7718,7 +8017,7 @@
* @dtopt Features
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* var oTable = $('#example').dataTable( {
* "sAjaxSource": "sources/arrays.txt",
* "bDeferRender": true
@@ -7738,7 +8037,7 @@
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "sScrollY": "200px",
* "bPaginate": false
@@ -7761,7 +8060,7 @@
* specified (this allow matching across multiple columns). Note that if you
* wish to use filtering in DataTables this must remain 'true' - to remove the
* default filtering input box and retain filtering abilities, please use
- * @ref{sDom}.
+ * {@link DataTable.defaults.sDom}.
* @type boolean
* @default true
* @dtopt Features
@@ -7877,7 +8176,7 @@
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* initTable();
* tableActions();
* } );
@@ -7909,7 +8208,7 @@
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bScrollAutoCss": false,
* "sScrollY": "200px"
@@ -7931,7 +8230,7 @@
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "sScrollY": "200",
* "bScrollCollapse": true
@@ -7953,7 +8252,7 @@
* @dtopt Features
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bScrollInfinite": true,
* "bScrollCollapse": true,
@@ -8010,7 +8309,7 @@
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bSortCellsTop": true
* } );
@@ -8097,7 +8396,7 @@
* @dtopt Callbacks
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "fnCreatedRow": function( nRow, aData, iDataIndex ) {
* // Bold the grade for all 'A' grade browsers
@@ -8122,7 +8421,7 @@
* @example
* $(document).ready( function() {
* $('#example').dataTable( {
- * "fnDrawCallback": function() {
+ * "fnDrawCallback": function( oSettings ) {
* alert( 'DataTables has redrawn the table' );
* }
* } );
@@ -8170,7 +8469,7 @@
* @dtopt Callbacks
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "fnFormatNumber": function ( iIn ) {
* if ( iIn < 1000 ) {
@@ -8329,7 +8628,7 @@
* @dtopt Callbacks
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
* // Bold the grade for all 'A' grade browsers
@@ -8362,13 +8661,13 @@
*
* @example
* // POST data to server
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bProcessing": true,
* "bServerSide": true,
* "sAjaxSource": "xhr.php",
- * "fnServerData": function ( sSource, aoData, fnCallback ) {
- * $.ajax( {
+ * "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
+ * oSettings.jqXHR = $.ajax( {
* "dataType": 'json',
* "type": "POST",
* "url": sSource,
@@ -8384,7 +8683,11 @@
"url": sUrl,
"data": aoData,
"success": function (json) {
- $(oSettings.oInstance).trigger('xhr', oSettings);
+ if ( json.sError ) {
+ oSettings.oApi._fnLog( oSettings, 0, json.sError );
+ }
+
+ $(oSettings.oInstance).trigger('xhr', [oSettings, json]);
fnCallback( json );
},
"dataType": "json",
@@ -8392,8 +8695,8 @@
"type": oSettings.sServerMethod,
"error": function (xhr, error, thrown) {
if ( error == "parsererror" ) {
- alert( "DataTables warning: JSON data from server could not be parsed. "+
- "This is caused by a JSON formatting error." );
+ oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
+ "server could not be parsed. This is caused by a JSON formatting error." );
}
}
} );
@@ -8418,7 +8721,7 @@
* @dtopt Server-side
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bProcessing": true,
* "bServerSide": true,
@@ -8443,10 +8746,10 @@
* @dtopt Callbacks
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bStateSave": true,
- * "fnStateSave": function (oSettings, oData) {
+ * "fnStateLoad": function (oSettings) {
* var o;
*
* // Send an Ajax request to the server to get the data. Note that
@@ -8493,21 +8796,23 @@
*
* @example
* // Remove a saved filter, so filtering is never loaded
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bStateSave": true,
* "fnStateLoadParams": function (oSettings, oData) {
- * oData.oFilter.sSearch = "";
+ * oData.oSearch.sSearch = "";
+ * }
* } );
* } );
*
* @example
* // Disallow state loading by returning false
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bStateSave": true,
* "fnStateLoadParams": function (oSettings, oData) {
* return false;
+ * }
* } );
* } );
*/
@@ -8524,11 +8829,12 @@
*
* @example
* // Show an alert with the filtering value that was saved
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bStateSave": true,
* "fnStateLoaded": function (oSettings, oData) {
- * alert( 'Saved filter was: '+oData.oFilter.sSearch );
+ * alert( 'Saved filter was: '+oData.oSearch.sSearch );
+ * }
* } );
* } );
*/
@@ -8546,7 +8852,7 @@
* @dtopt Callbacks
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bStateSave": true,
* "fnStateSave": function (oSettings, oData) {
@@ -8586,11 +8892,12 @@
*
* @example
* // Remove a saved filter, so filtering is never saved
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bStateSave": true,
- * "fnStateLoadParams": function (oSettings, oData) {
- * oData.oFilter.sSearch = "";
+ * "fnStateSaveParams": function (oSettings, oData) {
+ * oData.oSearch.sSearch = "";
+ * }
* } );
* } );
*/
@@ -8607,7 +8914,7 @@
* @example
* $(document).ready( function() {
* $('#example').dataTable( {
- * "iCookieDuration": 60*60*24 // 1 day
+ * "iCookieDuration": 60*60*24; // 1 day
* } );
* } )
*/
@@ -8620,19 +8927,38 @@
* will be applied to it), thus saving on an XHR at load time. iDeferLoading
* is used to indicate that deferred loading is required, but it is also used
* to tell DataTables how many records there are in the full table (allowing
- * the information element and pagination to be displayed correctly).
- * @type int
+ * the information element and pagination to be displayed correctly). In the case
+ * where a filtering is applied to the table on initial load, this can be
+ * indicated by giving the parameter as an array, where the first element is
+ * the number of records available after filtering and the second element is the
+ * number of records without filtering (allowing the table information element
+ * to be shown correctly).
+ * @type int | array
* @default null
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * // 57 records available in the table, no filtering applied
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bServerSide": true,
* "sAjaxSource": "scripts/server_processing.php",
* "iDeferLoading": 57
* } );
* } );
+ *
+ * @example
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "bServerSide": true,
+ * "sAjaxSource": "scripts/server_processing.php",
+ * "iDeferLoading": [ 57, 100 ],
+ * "oSearch": {
+ * "sSearch": "my_filter"
+ * }
+ * } );
+ * } );
*/
"iDeferLoading": null,
@@ -8684,7 +9010,7 @@
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "bScrollInfinite": true,
* "bScrollCollapse": true,
@@ -8708,7 +9034,7 @@
* @dtopt Options
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "iTabIndex": 1
* } );
@@ -8740,7 +9066,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "oAria": {
@@ -8761,7 +9087,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "oAria": {
@@ -8788,7 +9114,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "oPaginate": {
@@ -8809,7 +9135,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "oPaginate": {
@@ -8830,7 +9156,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "oPaginate": {
@@ -8851,7 +9177,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "oPaginate": {
@@ -8874,7 +9200,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sEmptyTable": "No data available in table"
@@ -8895,7 +9221,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
@@ -8914,7 +9240,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sInfoEmpty": "No entries to show"
@@ -8934,7 +9260,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sInfoFiltered": " - filtering from _MAX_ records"
@@ -8955,7 +9281,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sInfoPostFix": "All records shown are derived from real information."
@@ -8976,7 +9302,7 @@
* @dtopt Language
*
* @example
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sInfoThousands": "'"
@@ -8998,7 +9324,7 @@
*
* @example
* // Language change only
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sLengthMenu": "Display _MENU_ records"
@@ -9008,7 +9334,7 @@
*
* @example
* // Language and options change
- * $(document).ready(function() {
+ * $(document).ready( function() {
* $('#example').dataTable( {
* "oLanguage": {
* "sLengthMenu": 'Display
")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=i('')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),f,h,g,e,q,m,o,l=0;l")[0];q=d[l+1];if("'"==q||'"'==q){m="";for(o=2;d[l+o]!=q;)m+=d[l+o],
-o++;"H"==m?m="fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix":"F"==m&&(m="fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix");-1!=m.indexOf(".")?(q=m.split("."),e.id=q[0].substr(1,q[0].length-1),e.className=q[1]):"#"==m.charAt(0)?e.id=m.substr(1,m.length-1):e.className=m;l+=o}c.appendChild(e);c=e}else if(">"==g)c=c.parentNode;else if("l"==g&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)f=xa(a),h=1;else if("f"==g&&a.oFeatures.bFilter)f=
-ya(a),h=1;else if("r"==g&&a.oFeatures.bProcessing)f=za(a),h=1;else if("t"==g)f=Aa(a),h=1;else if("i"==g&&a.oFeatures.bInfo)f=Ba(a),h=1;else if("p"==g&&a.oFeatures.bPaginate)f=Ca(a),h=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;o=0;for(q=e.length;o'):""===c?'':c+' ',d=k.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="";if(!a.aanFeatures.f)d.id=a.sTableId+"_filter";c=i("input",
-d);c.val(b.sSearch.replace('"',"""));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=0,g=c.length;d=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||
-f.sSearch.length>b.length||1==c||0!==b.indexOf(f.sSearch)){a.aiDisplay.splice(0,a.aiDisplay.length);ia(a,1);for(b=0;b/g,""):"string"===typeof a?a.replace(/[\r\n]/g," "):null===a?"":a}function ma(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^)","g"),"\\$1")}function Ba(a){var b=k.createElement("div");b.className=a.oClasses.sInfo;if(!a.aanFeatures.i)a.aoDrawCallback.push({fn:Ia,sName:"information"}),b.id=a.sTableId+"_info";a.nTable.setAttribute("aria-describedby",
-a.sTableId+"_info");return b}function Ia(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a._iDisplayStart+1,c=a.fnDisplayEnd(),d=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),h=a.fnFormatNumber(b),g=a.fnFormatNumber(c),e=a.fnFormatNumber(d),q=a.fnFormatNumber(f);a.oScroll.bInfinite&&(h=a.fnFormatNumber(1));h=0===a.fnRecordsDisplay()&&a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfoEmpty+a.oLanguage.sInfoPostFix:0===a.fnRecordsDisplay()?a.oLanguage.sInfoEmpty+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",
-e)+a.oLanguage.sInfoPostFix:a.fnRecordsDisplay()==a.fnRecordsTotal()?a.oLanguage.sInfo.replace("_START_",h).replace("_END_",g).replace("_TOTAL_",q)+a.oLanguage.sInfoPostFix:a.oLanguage.sInfo.replace("_START_",h).replace("_END_",g).replace("_TOTAL_",q)+" "+a.oLanguage.sInfoFiltered.replace("_MAX_",a.fnFormatNumber(a.fnRecordsTotal()))+a.oLanguage.sInfoPostFix;null!==a.oLanguage.fnInfoCallback&&(h=a.oLanguage.fnInfoCallback.call(a.oInstance,a,b,c,d,f,h));a=a.aanFeatures.i;b=0;for(c=a.length;b",c,d,f=a.aLengthMenu;if(2==f.length&&"object"===typeof f[0]&&"object"===typeof f[1])for(c=0,d=f[0].length;c'+f[1][c]+"";else for(c=0,d=f.length;c'+f[c]+"";b+="";f=k.createElement("div");if(!a.aanFeatures.l)f.id=a.sTableId+"_length";f.className=a.oClasses.sLength;f.innerHTML="";
-i('select option[value="'+a._iDisplayLength+'"]',f).attr("selected",!0);i("select",f).bind("change.DT",function(){var b=i(this).val(),f=a.aanFeatures.l;for(c=0,d=f.length;ca._iDisplayStart))a._iDisplayStart=0;if(-1==a._iDisplayLength)a._iDisplayStart=0;y(a)});i("select",f).attr("aria-controls",a.sTableId);return f}
-function z(a){a._iDisplayEnd=!1===a.oFeatures.bPaginate?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength>a.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Ca(a){if(a.oScroll.bInfinite)return null;var b=k.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;j.ext.oPagination[a.sPaginationType].fnInit(a,b,function(a){z(a);y(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,
-function(a){z(a);y(a)})},sName:"pagination"});return b}function oa(a,b){var c=a._iDisplayStart;if("number"===typeof b){if(a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay())a._iDisplayStart=0}else if("first"==b)a._iDisplayStart=0;else if("previous"==b){if(a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-a._iDisplayLength:0,0>a._iDisplayStart)a._iDisplayStart=0}else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLengthi(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()=i.browser.version;g=a.nTable.getElementsByTagName("thead");0d.offsetHeight||"scroll"==i(d).css("overflow-y")))a.nTable.style.width=
-p(i(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else if(""!==a.oScroll.sXInner)a.nTable.style.width=p(a.oScroll.sXInner);else if(f==i(d).width()&&i(d).height()f-a.oScroll.iBarWidth)a.nTable.style.width=p(f)}else a.nTable.style.width=p(f);f=i(a.nTable).outerWidth();h=a.nTHead.getElementsByTagName("tr");g=g.getElementsByTagName("tr");N(function(a,b){m=a.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth=
-"0";m.borderBottomWidth="0";m.height=0;l=i(a).width();b.style.width=p(l);r.push(l)},g,h);i(g).height(0);null!==a.nTFoot&&(e=j.getElementsByTagName("tr"),j=a.nTFoot.getElementsByTagName("tr"),N(function(a,b){m=a.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";m.height=0;l=i(a).width();b.style.width=p(l);r.push(l)},e,j),i(e).height(0));N(function(a){a.innerHTML="";a.style.width=p(r.shift())},g);null!==a.nTFoot&&N(function(a){a.innerHTML="";a.style.width=p(r.shift())},
-e);if(i(a.nTable).outerWidth()d.offsetHeight||"scroll"==i(d).css("overflow-y")?f+a.oScroll.iBarWidth:f;if(k&&(d.scrollHeight>d.offsetHeight||"scroll"==i(d).css("overflow-y")))a.nTable.style.width=p(e-a.oScroll.iBarWidth);d.style.width=p(e);b.parentNode.style.width=p(e);if(null!==a.nTFoot)n.parentNode.style.width=p(e);""===a.oScroll.sX?F(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."):
-""!==a.oScroll.sXInner&&F(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else if(d.style.width=p("100%"),b.parentNode.style.width=p("100%"),null!==a.nTFoot)n.parentNode.style.width=p("100%");if(""===a.oScroll.sY&&k)d.style.height=p(a.nTable.offsetHeight+a.oScroll.iBarWidth);if(""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=p(a.oScroll.sY),k=""!==a.oScroll.sX&&a.nTable.offsetWidth>
-d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeighttd",b));g=O(a,
-h);for(h=d=0;hc)return null;if(null===a.aoData[c].nTr){var d=k.createElement("td");d.innerHTML=w(a,c,b,"");return d}return L(a,c)[b]}function Na(a,b){for(var c=-1,d=-1,f=0;f/g,"");if(h.length>c)c=h.length,d=f}return d}function p(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1);return 48>b||57=g)for(b=0;be&&e++}}}function pa(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b,c;b=a.oScroll.bInfinite;var d={iCreate:(new Date).getTime(),iStart:b?0:a._iDisplayStart,
-iEnd:b?a._iDisplayLength:a._iDisplayEnd,iLength:a._iDisplayLength,aaSorting:i.extend(!0,[],a.aaSorting),oSearch:i.extend(!0,{},a.oPreviousSearch),aoSearchCols:i.extend(!0,[],a.aoPreSearchCols),abVisCols:[]};for(b=0,c=a.aoColumns.length;b=d.aiDisplay.length&&(d._iDisplayStart-=d._iDisplayLength,0>d._iDisplayStart))d._iDisplayStart=0;if(c===l||c)z(d),y(d);return e};this.fnDestroy=function(a){var b=u(this[j.ext.iApiIndex]),c=b.nTableWrapper.parentNode,d=b.nTBody,f,e,a=a===l?!1:!0;b.bDestroying=!0;for(f=0,e=b.aoDestroyCallback.length;ftr>td."+b.oClasses.sRowEmpty,b.nTable).parent().remove();b.nTable!=b.nTHead.parentNode&&(i(b.nTable).children("thead").remove(),b.nTable.appendChild(b.nTHead));b.nTFoot&&b.nTable!=b.nTFoot.parentNode&&(i(b.nTable).children("tfoot").remove(),b.nTable.appendChild(b.nTFoot));b.nTable.parentNode.removeChild(b.nTable);i(b.nTableWrapper).remove();b.aaSorting=
-[];b.aaSortingFixed=[];Q(b);i(S(b)).removeClass(b.asStripeClasses.join(" "));i("th, td",b.nTHead).removeClass([b.oClasses.sSortable,b.oClasses.sSortableAsc,b.oClasses.sSortableDesc,b.oClasses.sSortableNone].join(" "));b.bJUI&&(i("th span."+b.oClasses.sSortIcon+", td span."+b.oClasses.sSortIcon,b.nTHead).remove(),i("th, td",b.nTHead).each(function(){var a=i("div."+b.oClasses.sSortJUIWrapper,this),c=a.contents();i(this).append(c);a.remove()}));!a&&b.nTableReinsertBefore?c.insertBefore(b.nTable,b.nTableReinsertBefore):
-a||c.appendChild(b.nTable);for(f=0,e=b.aoData.length;f=v(d);if(!m)for(f=a;ft<"F"ip>'}else i.extend(g.oClasses,j.ext.oStdClasses);i(this).addClass(g.oClasses.sTable);if(""!==g.oScroll.sX||""!==g.oScroll.sY)g.oScroll.iBarWidth=Oa();if(g.iInitDisplayStart===l)g.iInitDisplayStart=e.iDisplayStart,g._iDisplayStart=e.iDisplayStart;if(e.bStateSave)g.oFeatures.bStateSave=!0,Qa(g,e),A(g,"aoDrawCallback",pa,"state_save");if(null!==e.iDeferLoading)g.bDeferLoading=!0,g._iRecordsTotal=e.iDeferLoading,
-g._iRecordsDisplay=e.iDeferLoading;null!==e.aaData&&(h=!0);""!==e.oLanguage.sUrl?(g.oLanguage.sUrl=e.oLanguage.sUrl,i.getJSON(g.oLanguage.sUrl,null,function(a){na(a);i.extend(!0,g.oLanguage,e.oLanguage,a);$(g)}),f=!0):i.extend(!0,g.oLanguage,e.oLanguage);c=!1;d=i(this).children("tbody").children("tr");for(a=0,b=g.asStripeClasses.length;a=g.aoColumns.length&&(g.aaSorting[a][0]=0);var r=g.aoColumns[g.aaSorting[a][0]];g.aaSorting[a][2]===l&&(g.aaSorting[a][2]=0);e.aaSorting===l&&g.saved_aaSorting===l&&(g.aaSorting[a][1]=r.asSorting[0]);for(c=0,d=r.asSorting.length;c<
-d;c++)if(g.aaSorting[a][1]==r.asSorting[c]){g.aaSorting[a][2]=c;break}}Q(g);a=i(this).children("thead");0===a.length&&(a=[k.createElement("thead")],this.appendChild(a[0]));g.nTHead=a[0];a=i(this).children("tbody");0===a.length&&(a=[k.createElement("tbody")],this.appendChild(a[0]));g.nTBody=a[0];g.nTBody.setAttribute("role","alert");g.nTBody.setAttribute("aria-live","polite");g.nTBody.setAttribute("aria-relevant","all");a=i(this).children("tfoot");if(0=parseInt(k,10)},iApiIndex:0,ofnSearch:{},oApi:{},
-oStdClasses:{},oJUIClasses:{},oPagination:{},oSort:{},sVersion:j.version,sErrMode:"alert",_oExternConfig:{iNextUnique:0}};j.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};j.models.oRow={nTr:null,_aData:[],_aSortData:[],_anHidden:[],_sRowStripe:""};j.models.oColumn={aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bUseRendered:null,bVisible:null,_bAutoType:!0,fnCreatedCell:null,fnGetData:null,fnRender:null,fnSetData:null,mDataProp:null,nTh:null,nTf:null,sClass:null,
-sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};j.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:["odd","even"],bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollAutoCss:!0,bScrollCollapse:!1,
-bScrollInfinite:!1,bServerSide:!1,bSort:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCookieCallback:null,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(e){if(1E3>e)return e;for(var i=e+"",e=i.split(""),j="",i=i.length,l=0;lm[f])d(a.aoColumns.length+m[f],b[h]);else if("string"===typeof m[f]){e=0;for(s=a.aoColumns.length;eb&&a[d]--; -1!=c&&a.splice(c,1)}function T(a,b,c){var d=a.aoColumns[c];return d.fnRender({iDataRow:b,iDataColumn:c,oSettings:a,aData:a.aoData[b]._aData,mDataProp:d.mData},x(a,b,c,"display"))}function da(a,b){var c=a.aoData[b],d;if(null===c.nTr){c.nTr=l.createElement("tr");c.nTr._DT_RowIndex=b;c._aData.DT_RowId&&(c.nTr.id=c._aData.DT_RowId);c._aData.DT_RowClass&&
+i(c.nTr).addClass(c._aData.DT_RowClass);for(var h=0,f=a.aoColumns.length;h=a.fnRecordsDisplay()?0:a.iInitDisplayStart,a.iInitDisplayStart=-1,A(a));if(a.bDeferLoading)a.bDeferLoading=!1,a.iDraw++;else if(a.oFeatures.bServerSide){if(!a.bDestroying&&!xa(a))return}else a.iDraw++;if(0!==a.aiDisplay.length){var g=
+a._iDisplayStart;d=a._iDisplayEnd;a.oFeatures.bServerSide&&(g=0,d=a.aoData.length);for(;g")[0];a.nTable.parentNode.insertBefore(b,a.nTable);a.nTableWrapper=i('')[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var c=a.nTableWrapper,d=a.sDom.split(""),h,f,g,e,s,m,o,k=0;k")[0];s=d[k+
+1];if("'"==s||'"'==s){m="";for(o=2;d[k+o]!=s;)m+=d[k+o],o++;"H"==m?m=a.oClasses.sJUIHeader:"F"==m&&(m=a.oClasses.sJUIFooter);-1!=m.indexOf(".")?(s=m.split("."),e.id=s[0].substr(1,s[0].length-1),e.className=s[1]):"#"==m.charAt(0)?e.id=m.substr(1,m.length-1):e.className=m;k+=o}c.appendChild(e);c=e}else if(">"==g)c=c.parentNode;else if("l"==g&&a.oFeatures.bPaginate&&a.oFeatures.bLengthChange)h=za(a),f=1;else if("f"==g&&a.oFeatures.bFilter)h=Aa(a),f=1;else if("r"==g&&a.oFeatures.bProcessing)h=Ba(a),f=
+1;else if("t"==g)h=Ca(a),f=1;else if("i"==g&&a.oFeatures.bInfo)h=Da(a),f=1;else if("p"==g&&a.oFeatures.bPaginate)h=Ea(a),f=1;else if(0!==j.ext.aoFeatures.length){e=j.ext.aoFeatures;o=0;for(s=e.length;o'):""===c?'':c+' ',d=l.createElement("div");d.className=a.oClasses.sFilter;d.innerHTML="";a.aanFeatures.f||(d.id=a.sTableId+"_filter");c=i('input[type="text"]',d);d._DT_Input=c[0];c.val(b.sSearch.replace('"',"""));c.bind("keyup.DT",function(){for(var c=a.aanFeatures.f,d=this.value===""?"":this.value,
+g=0,e=c.length;g=b.length)a.aiDisplay.splice(0,a.aiDisplay.length),a.aiDisplay=a.aiDisplayMaster.slice();else if(a.aiDisplay.length==a.aiDisplayMaster.length||h.sSearch.length>b.length||1==c||0!==b.indexOf(h.sSearch)){a.aiDisplay.splice(0,
+a.aiDisplay.length);ka(a,1);for(b=0;b").html(c).text());
+return c.replace(/[\n\r]/g," ")}function la(a,b,c,d){if(c)return a=b?a.split(" "):na(a).split(" "),a="^(?=.*?"+a.join(")(?=.*?")+").*$",RegExp(a,d?"i":"");a=b?a:na(a);return RegExp(a,d?"i":"")}function Ka(a,b){return"function"===typeof j.ext.ofnSearch[b]?j.ext.ofnSearch[b](a):null===a?"":"html"==b?a.replace(/[\r\n]/g," ").replace(/<.*?>/g,""):"string"===typeof a?a.replace(/[\r\n]/g," "):a}function na(a){return a.replace(RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),
+"\\$1")}function Da(a){var b=l.createElement("div");b.className=a.oClasses.sInfo;a.aanFeatures.i||(a.aoDrawCallback.push({fn:La,sName:"information"}),b.id=a.sTableId+"_info");a.nTable.setAttribute("aria-describedby",a.sTableId+"_info");return b}function La(a){if(a.oFeatures.bInfo&&0!==a.aanFeatures.i.length){var b=a.oLanguage,c=a._iDisplayStart+1,d=a.fnDisplayEnd(),h=a.fnRecordsTotal(),f=a.fnRecordsDisplay(),g;g=0===f&&f==h?b.sInfoEmpty:0===f?b.sInfoEmpty+" "+b.sInfoFiltered:f==h?b.sInfo:b.sInfo+
+" "+b.sInfoFiltered;g+=b.sInfoPostFix;g=ia(a,g);null!==b.fnInfoCallback&&(g=b.fnInfoCallback.call(a.oInstance,a,c,d,h,f,g));a=a.aanFeatures.i;b=0;for(c=a.length;b",c,d,h=a.aLengthMenu;if(2==h.length&&"object"===typeof h[0]&&"object"===typeof h[1]){c=0;for(d=h[0].length;c'+h[1][c]+""}else{c=0;for(d=h.length;c'+h[c]+""}b+=
+"";h=l.createElement("div");a.aanFeatures.l||(h.id=a.sTableId+"_length");h.className=a.oClasses.sLength;h.innerHTML="";i('select option[value="'+a._iDisplayLength+'"]',h).attr("selected",!0);i("select",h).bind("change.DT",function(){var b=i(this).val(),h=a.aanFeatures.l;c=0;for(d=h.length;ca.aiDisplay.length||-1==a._iDisplayLength?a.aiDisplay.length:a._iDisplayStart+a._iDisplayLength}function Ea(a){if(a.oScroll.bInfinite)return null;var b=l.createElement("div");b.className=a.oClasses.sPaging+a.sPaginationType;
+j.ext.oPagination[a.sPaginationType].fnInit(a,b,function(a){A(a);z(a)});a.aanFeatures.p||a.aoDrawCallback.push({fn:function(a){j.ext.oPagination[a.sPaginationType].fnUpdate(a,function(a){A(a);z(a)})},sName:"pagination"});return b}function pa(a,b){var c=a._iDisplayStart;if("number"===typeof b)a._iDisplayStart=b*a._iDisplayLength,a._iDisplayStart>a.fnRecordsDisplay()&&(a._iDisplayStart=0);else if("first"==b)a._iDisplayStart=0;else if("previous"==b)a._iDisplayStart=0<=a._iDisplayLength?a._iDisplayStart-
+a._iDisplayLength:0,0>a._iDisplayStart&&(a._iDisplayStart=0);else if("next"==b)0<=a._iDisplayLength?a._iDisplayStart+a._iDisplayLengthi(a.nTable).height()-a.oScroll.iLoadGap&&a.fnDisplayEnd()d.offsetHeight||"scroll"==i(d).css("overflow-y")))a.nTable.style.width=q(i(a.nTable).outerWidth()-a.oScroll.iBarWidth)}else""!==a.oScroll.sXInner?a.nTable.style.width=q(a.oScroll.sXInner):h==i(d).width()&&i(d).height()h-a.oScroll.iBarWidth&&
+(a.nTable.style.width=q(h))):a.nTable.style.width=q(h);h=i(a.nTable).outerWidth();f=a.nTHead.getElementsByTagName("tr");g=g.getElementsByTagName("tr");N(function(a,b){m=a.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth="0";m.borderBottomWidth="0";m.height=0;k=i(a).width();b.style.width=q(k);r.push(k)},g,f);i(g).height(0);null!==a.nTFoot&&(e=j.getElementsByTagName("tr"),j=a.nTFoot.getElementsByTagName("tr"),N(function(a,b){m=a.style;m.paddingTop="0";m.paddingBottom="0";m.borderTopWidth=
+"0";m.borderBottomWidth="0";m.height=0;k=i(a).width();b.style.width=q(k);r.push(k)},e,j),i(e).height(0));N(function(a){a.innerHTML="";a.style.width=q(r.shift())},g);null!==a.nTFoot&&N(function(a){a.innerHTML="";a.style.width=q(r.shift())},e);if(i(a.nTable).outerWidth()d.offsetHeight||"scroll"==i(d).css("overflow-y")?h+a.oScroll.iBarWidth:h;if(l&&(d.scrollHeight>d.offsetHeight||"scroll"==i(d).css("overflow-y")))a.nTable.style.width=q(e-a.oScroll.iBarWidth);d.style.width=q(e);b.parentNode.style.width=
+q(e);null!==a.nTFoot&&(n.parentNode.style.width=q(e));""===a.oScroll.sX?E(a,1,"The table cannot fit into the current element which will cause column misalignment. The table has been drawn at its minimum possible width."):""!==a.oScroll.sXInner&&E(a,1,"The table cannot fit into the current element which will cause column misalignment. Increase the sScrollXInner value or remove it to allow automatic calculation")}else d.style.width=q("100%"),b.parentNode.style.width=q("100%"),null!==a.nTFoot&&(n.parentNode.style.width=
+q("100%"));""===a.oScroll.sY&&l&&(d.style.height=q(a.nTable.offsetHeight+a.oScroll.iBarWidth));""!==a.oScroll.sY&&a.oScroll.bCollapse&&(d.style.height=q(a.oScroll.sY),l=""!==a.oScroll.sX&&a.nTable.offsetWidth>d.offsetWidth?a.oScroll.iBarWidth:0,a.nTable.offsetHeightd.clientHeight||"scroll"==i(d).css("overflow-y");b.style.paddingRight=c?a.oScroll.iBarWidth+
+"px":"0px";null!==a.nTFoot&&(p.style.width=q(l),n.style.width=q(l),n.style.paddingRight=c?a.oScroll.iBarWidth+"px":"0px");i(d).scroll();if(a.bSorted||a.bFiltered)d.scrollTop=0}function N(a,b,c){for(var d=0,h=b.length;dtd",b));g=P(a,f);for(f=d=0;fc)return null;if(null===a.aoData[c].nTr){var d=l.createElement("td");d.innerHTML=x(a,c,b,"");return d}return L(a,c)[b]}function Qa(a,b){for(var c=
+-1,d=-1,h=0;h/g,"");f.length>c&&(c=f.length,d=h)}return d}function q(a){if(null===a)return"0px";if("number"==typeof a)return 0>a?"0px":a+"px";var b=a.charCodeAt(a.length-1);return 48>b||57/g,""),h=l[c].nTh,h.removeAttribute("aria-sort"),h.removeAttribute("aria-label"),l[c].bSortable?0=e)for(b=0;bj&&j++}}}function qa(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b,c;b=a.oScroll.bInfinite;var d={iCreate:(new Date).getTime(),iStart:b?0:a._iDisplayStart,
+iEnd:b?a._iDisplayLength:a._iDisplayEnd,iLength:a._iDisplayLength,aaSorting:i.extend(!0,[],a.aaSorting),oSearch:i.extend(!0,{},a.oPreviousSearch),aoSearchCols:i.extend(!0,[],a.aoPreSearchCols),abVisCols:[]};b=0;for(c=a.aoColumns.length;b