Skip to content

Commit

Permalink
New: DataTables now uses HTML5 localStorage by default for state sa…
Browse files Browse the repository at this point in the history
…ving. This has a number of advantages over cookies, the first of which is that we are no longer limited to 4KiB in size. It also makes HTTP requests faster since they aren't included in the HTTP transport. Better yet, the removal of the cookie code reduces the DataTables minified size by 1.5K (1573 bytes). It must be noted that this does mean that IE6/7 don't, by default, work with state saving in DataTables. If support for those browsers is required, then fnStateSaveCallback and fnStateLoadCallback must be used by the developer to define their own state saving methods.

Removed: fnCookieCallback (cookieCallback) - This is now irrelevant since DataTables does not state save in cookies by default.

Removed: sCookiePrefix (cookiePrefix) - This is now irrelevant since DataTables does not state save in cookies by default.

Depreciated: iCookieDuration (cookieDuration) - Since DataTables does not use cookies for state saving by default the name of this parameter is now incorrect. The new parameter `stateDuration` should be used instead, although the old parameter is still supported. It will be removed in the next major version of DataTables.
  • Loading branch information
Allan Jardine committed Oct 31, 2012
1 parent c883cda commit 94f0647
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 570 deletions.
330 changes: 45 additions & 285 deletions media/js/jquery.dataTables.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion media/src/DataTables.js
Expand Up @@ -21,7 +21,7 @@
*/ */


/*jslint evil: true, undef: true, browser: true */ /*jslint evil: true, undef: true, browser: true */
/*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns,_fnHungarianMap,_fnCamelToHungarian*/ /*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns,_fnHungarianMap,_fnCamelToHungarian*/


(/** @lends <global> */function( window, document, undefined ) { (/** @lends <global> */function( window, document, undefined ) {


Expand Down
3 changes: 0 additions & 3 deletions media/src/api/api.internal.js
Expand Up @@ -92,8 +92,6 @@ this.oApi = {
"_fnClearTable": _fnClearTable, "_fnClearTable": _fnClearTable,
"_fnSaveState": _fnSaveState, "_fnSaveState": _fnSaveState,
"_fnLoadState": _fnLoadState, "_fnLoadState": _fnLoadState,
"_fnCreateCookie": _fnCreateCookie,
"_fnReadCookie": _fnReadCookie,
"_fnDetectHeader": _fnDetectHeader, "_fnDetectHeader": _fnDetectHeader,
"_fnGetUniqueThs": _fnGetUniqueThs, "_fnGetUniqueThs": _fnGetUniqueThs,
"_fnScrollBarWidth": _fnScrollBarWidth, "_fnScrollBarWidth": _fnScrollBarWidth,
Expand All @@ -109,7 +107,6 @@ this.oApi = {
"_fnExtend": _fnExtend, "_fnExtend": _fnExtend,
"_fnCallbackReg": _fnCallbackReg, "_fnCallbackReg": _fnCallbackReg,
"_fnCallbackFire": _fnCallbackFire, "_fnCallbackFire": _fnCallbackFire,
"_fnJsonString": _fnJsonString,
"_fnNodeToColumnIndex": _fnNodeToColumnIndex, "_fnNodeToColumnIndex": _fnNodeToColumnIndex,
"_fnInfoMacros": _fnInfoMacros, "_fnInfoMacros": _fnInfoMacros,
"_fnBrowserDetect": _fnBrowserDetect, "_fnBrowserDetect": _fnBrowserDetect,
Expand Down
11 changes: 5 additions & 6 deletions media/src/core/core.constructor.js
Expand Up @@ -118,18 +118,17 @@ _fnMap( oSettings, oInit, "aLengthMenu" );
_fnMap( oSettings, oInit, "sPaginationType" ); _fnMap( oSettings, oInit, "sPaginationType" );
_fnMap( oSettings, oInit, "sAjaxSource" ); _fnMap( oSettings, oInit, "sAjaxSource" );
_fnMap( oSettings, oInit, "sAjaxDataProp" ); _fnMap( oSettings, oInit, "sAjaxDataProp" );
_fnMap( oSettings, oInit, "iCookieDuration" ); _fnMap( oSettings, oInit, "iCookieDuration", "iStateDuration" ); // backwards compat
_fnMap( oSettings, oInit, "sCookiePrefix" ); _fnMap( oSettings, oInit, "iStateDuration" );
_fnMap( oSettings, oInit, "sDom" ); _fnMap( oSettings, oInit, "sDom" );
_fnMap( oSettings, oInit, "bSortCellsTop" ); _fnMap( oSettings, oInit, "bSortCellsTop" );
_fnMap( oSettings, oInit, "iTabIndex" ); _fnMap( oSettings, oInit, "iTabIndex" );
_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" ); _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" ); _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" ); _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
_fnMap( oSettings, oInit, "bJQueryUI", "bJUI" ); _fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
_fnMap( oSettings, oInit, "fnCookieCallback" ); _fnMap( oSettings, oInit, "fnStateLoadCallback" );
_fnMap( oSettings, oInit, "fnStateLoad" ); _fnMap( oSettings, oInit, "fnStateSaveCallback" );
_fnMap( oSettings, oInit, "fnStateSave" );
_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );


/* Callback functions which are array driven */ /* Callback functions which are array driven */
Expand Down Expand Up @@ -190,7 +189,7 @@ if ( oSettings.iInitDisplayStart === undefined )
oSettings._iDisplayStart = oInit.iDisplayStart; oSettings._iDisplayStart = oInit.iDisplayStart;
} }


/* Must be done after everything which can be overridden by a cookie! */ /* Must be done after everything which can be overridden by the state saving! */
if ( oInit.bStateSave ) if ( oInit.bStateSave )
{ {
oSettings.oFeatures.bStateSave = true; oSettings.oFeatures.bStateSave = true;
Expand Down
133 changes: 9 additions & 124 deletions media/src/core/core.state.js
@@ -1,7 +1,7 @@




/** /**
* Save the state of a table in a cookie such that the page can be reloaded * Save the state of a table
* @param {object} oSettings dataTables settings object * @param {object} oSettings dataTables settings object
* @memberof DataTable#oApi * @memberof DataTable#oApi
*/ */
Expand Down Expand Up @@ -32,12 +32,12 @@ function _fnSaveState ( oSettings )


_fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] ); _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );


oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState ); oSettings.fnStateSaveCallback.call( oSettings.oInstance, oSettings, oState );
} }




/** /**
* Attempt to load a saved table state from a cookie * Attempt to load a saved table state
* @param {object} oSettings dataTables settings object * @param {object} oSettings dataTables settings object
* @param {object} oInit DataTables init object so we can override settings * @param {object} oInit DataTables init object so we can override settings
* @memberof DataTable#oApi * @memberof DataTable#oApi
Expand All @@ -49,7 +49,7 @@ function _fnLoadState ( oSettings, oInit )
return; return;
} }


var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings ); var oData = oSettings.fnStateLoadCallback.call( oSettings.oInstance, oSettings );
if ( !oData ) if ( !oData )
{ {
return; return;
Expand All @@ -63,6 +63,11 @@ function _fnLoadState ( oSettings, oInit )
{ {
return; return;
} }

/* Reject old data */
if ( oData.iCreate < new Date().getTime() - (oSettings.iStateDuration*1000) ) {
return;
}


/* Store the saved state so it might be accessed at any time */ /* Store the saved state so it might be accessed at any time */
oSettings.oLoadedState = $.extend( true, {}, oData ); oSettings.oLoadedState = $.extend( true, {}, oData );
Expand Down Expand Up @@ -94,123 +99,3 @@ function _fnLoadState ( oSettings, oInit )
} }




/**
* Create a new cookie with a value to store the state of a table
* @param {string} sName name of the cookie to create
* @param {string} sValue the value the cookie should take
* @param {int} iSecs duration of the cookie
* @param {string} sBaseName sName is made up of the base + file name - this is the base
* @param {function} fnCallback User definable function to modify the cookie
* @memberof DataTable#oApi
*/
function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
{
var date = new Date();
date.setTime( date.getTime()+(iSecs*1000) );

/*
* Shocking but true - it would appear IE has major issues with having the path not having
* a trailing slash on it. We need the cookie to be available based on the path, so we
* have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
* patch to use at least some of the path
*/
var aParts = window.location.pathname.split('/');
var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
var sFullCookie, oData;

if ( fnCallback !== null )
{
oData = (typeof $.parseJSON === 'function') ?
$.parseJSON( sValue ) : eval( '('+sValue+')' );
sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
aParts.join('/')+"/" );
}
else
{
sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
"; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
}

/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
* belonging to DataTables.
*/
var
aCookies =document.cookie.split(';'),
iNewCookieLen = sFullCookie.split(';')[0].length,
aOldCookies = [];

if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
{
for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
{
if ( aCookies[i].indexOf( sBaseName ) != -1 )
{
/* It's a DataTables cookie, so eval it and check the time stamp */
var aSplitCookie = aCookies[i].split('=');
try {
oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );

if ( oData && oData.iCreate )
{
aOldCookies.push( {
"name": aSplitCookie[0],
"time": oData.iCreate
} );
}
}
catch( e ) {}
}
}

// Make sure we delete the oldest ones first
aOldCookies.sort( function (a, b) {
return b.time - a.time;
} );

// Eliminate as many old DataTables cookies as we need to
while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
if ( aOldCookies.length === 0 ) {
// Deleted all DT cookies and still not enough space. Can't state save
return;
}

var old = aOldCookies.pop();
document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
aParts.join('/') + "/";
}
}

document.cookie = sFullCookie;
}


/**
* Read an old cookie to get a cookie with an old table state
* @param {string} sName name of the cookie to read
* @returns {string} contents of the cookie - or null if no cookie with that name found
* @memberof DataTable#oApi
*/
function _fnReadCookie ( sName )
{
var
aParts = window.location.pathname.split('/'),
sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
sCookieContents = document.cookie.split(';');

for( var i=0 ; i<sCookieContents.length ; i++ )
{
var c = sCookieContents[i];

while (c.charAt(0)==' ')
{
c = c.substring(1,c.length);
}

if (c.indexOf(sNameEQ) === 0)
{
return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
}
}
return null;
}

52 changes: 0 additions & 52 deletions media/src/core/core.support.js
Expand Up @@ -268,58 +268,6 @@ function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
} }




/**
* 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 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.
* @param {object} o JSON object to be converted
* @returns {string} JSON string
* @memberof DataTable#oApi
*/
var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
{
/* Not an object or array */
var sType = typeof o;
if (sType !== "object" || o === null)
{
// simple data type
if (sType === "string")
{
o = '"'+o+'"';
}
return o+"";
}

/* If object or array, need to recurse over it */
var
sProp, mValue,
json = [],
bArr = $.isArray(o);

for (sProp in o)
{
mValue = o[sProp];
sType = typeof mValue;

if (sType === "string")
{
mValue = '"'+mValue+'"';
}
else if (sType === "object" && mValue !== null)
{
mValue = _fnJsonString(mValue);
}

json.push((bArr ? "" : '"'+sProp+'":') + mValue);
}

return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
};


/** /**
* From some browsers (specifically IE6/7) we need special handling to work around browser * 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. * bugs - this function is used to detect when these workarounds are needed.
Expand Down

0 comments on commit 94f0647

Please sign in to comment.