1
|
|
2
|
|
3
|
/**
|
4
|
* Save the state of a table in a cookie such that the page can be reloaded
|
5
|
* @param {object} oSettings dataTables settings object
|
6
|
* @memberof DataTable#oApi
|
7
|
*/
|
8
|
function _fnSaveState ( oSettings )
|
9
|
{
|
10
|
if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
|
11
|
{
|
12
|
return;
|
13
|
}
|
14
|
|
15
|
/* Store the interesting variables */
|
16
|
var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
|
17
|
var oState = {
|
18
|
"iCreate": new Date().getTime(),
|
19
|
"iStart": (bInfinite ? 0 : oSettings._iDisplayStart),
|
20
|
"iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
|
21
|
"iLength": oSettings._iDisplayLength,
|
22
|
"aaSorting": $.extend( true, [], oSettings.aaSorting ),
|
23
|
"oSearch": $.extend( true, {}, oSettings.oPreviousSearch ),
|
24
|
"aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
|
25
|
"abVisCols": []
|
26
|
};
|
27
|
|
28
|
for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
|
29
|
{
|
30
|
oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
|
31
|
}
|
32
|
|
33
|
_fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
|
34
|
|
35
|
oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
|
36
|
}
|
37
|
|
38
|
|
39
|
/**
|
40
|
* Attempt to load a saved table state from a cookie
|
41
|
* @param {object} oSettings dataTables settings object
|
42
|
* @param {object} oInit DataTables init object so we can override settings
|
43
|
* @memberof DataTable#oApi
|
44
|
*/
|
45
|
function _fnLoadState ( oSettings, oInit )
|
46
|
{
|
47
|
if ( !oSettings.oFeatures.bStateSave )
|
48
|
{
|
49
|
return;
|
50
|
}
|
51
|
|
52
|
var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
|
53
|
if ( !oData )
|
54
|
{
|
55
|
return;
|
56
|
}
|
57
|
|
58
|
/* Allow custom and plug-in manipulation functions to alter the saved data set and
|
59
|
* cancelling of loading by returning false
|
60
|
*/
|
61
|
var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
|
62
|
if ( $.inArray( false, abStateLoad ) !== -1 )
|
63
|
{
|
64
|
return;
|
65
|
}
|
66
|
|
67
|
/* Store the saved state so it might be accessed at any time */
|
68
|
oSettings.oLoadedState = $.extend( true, {}, oData );
|
69
|
|
70
|
/* Restore key features */
|
71
|
oSettings._iDisplayStart = oData.iStart;
|
72
|
oSettings.iInitDisplayStart = oData.iStart;
|
73
|
oSettings._iDisplayEnd = oData.iEnd;
|
74
|
oSettings._iDisplayLength = oData.iLength;
|
75
|
oSettings.aaSorting = oData.aaSorting.slice();
|
76
|
oSettings.saved_aaSorting = oData.aaSorting.slice();
|
77
|
|
78
|
/* Search filtering */
|
79
|
$.extend( oSettings.oPreviousSearch, oData.oSearch );
|
80
|
$.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
|
81
|
|
82
|
/* Column visibility state
|
83
|
* Pass back visibility settings to the init handler, but to do not here override
|
84
|
* the init object that the user might have passed in
|
85
|
*/
|
86
|
oInit.saved_aoColumns = [];
|
87
|
for ( var i=0 ; i<oData.abVisCols.length ; i++ )
|
88
|
{
|
89
|
oInit.saved_aoColumns[i] = {};
|
90
|
oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
|
91
|
}
|
92
|
|
93
|
_fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
|
94
|
}
|
95
|
|
96
|
|
97
|
/**
|
98
|
* Create a new cookie with a value to store the state of a table
|
99
|
* @param {string} sName name of the cookie to create
|
100
|
* @param {string} sValue the value the cookie should take
|
101
|
* @param {int} iSecs duration of the cookie
|
102
|
* @param {string} sBaseName sName is made up of the base + file name - this is the base
|
103
|
* @param {function} fnCallback User definable function to modify the cookie
|
104
|
* @memberof DataTable#oApi
|
105
|
*/
|
106
|
function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
|
107
|
{
|
108
|
var date = new Date();
|
109
|
date.setTime( date.getTime()+(iSecs*1000) );
|
110
|
|
111
|
/*
|
112
|
* Shocking but true - it would appear IE has major issues with having the path not having
|
113
|
* a trailing slash on it. We need the cookie to be available based on the path, so we
|
114
|
* have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
|
115
|
* patch to use at least some of the path
|
116
|
*/
|
117
|
var aParts = window.location.pathname.split('/');
|
118
|
var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
|
119
|
var sFullCookie, oData;
|
120
|
|
121
|
if ( fnCallback !== null )
|
122
|
{
|
123
|
oData = (typeof $.parseJSON === 'function') ?
|
124
|
$.parseJSON( sValue ) : eval( '('+sValue+')' );
|
125
|
sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
|
126
|
aParts.join('/')+"/" );
|
127
|
}
|
128
|
else
|
129
|
{
|
130
|
sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
|
131
|
"; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
|
132
|
}
|
133
|
|
134
|
/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
|
135
|
* belonging to DataTables.
|
136
|
*/
|
137
|
var
|
138
|
aCookies =document.cookie.split(';'),
|
139
|
iNewCookieLen = sFullCookie.split(';')[0].length,
|
140
|
aOldCookies = [];
|
141
|
|
142
|
if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
|
143
|
{
|
144
|
for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
|
145
|
{
|
146
|
if ( aCookies[i].indexOf( sBaseName ) != -1 )
|
147
|
{
|
148
|
/* It's a DataTables cookie, so eval it and check the time stamp */
|
149
|
var aSplitCookie = aCookies[i].split('=');
|
150
|
try {
|
151
|
oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );
|
152
|
|
153
|
if ( oData && oData.iCreate )
|
154
|
{
|
155
|
aOldCookies.push( {
|
156
|
"name": aSplitCookie[0],
|
157
|
"time": oData.iCreate
|
158
|
} );
|
159
|
}
|
160
|
}
|
161
|
catch( e ) {}
|
162
|
}
|
163
|
}
|
164
|
|
165
|
// Make sure we delete the oldest ones first
|
166
|
aOldCookies.sort( function (a, b) {
|
167
|
return b.time - a.time;
|
168
|
} );
|
169
|
|
170
|
// Eliminate as many old DataTables cookies as we need to
|
171
|
while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
|
172
|
if ( aOldCookies.length === 0 ) {
|
173
|
// Deleted all DT cookies and still not enough space. Can't state save
|
174
|
return;
|
175
|
}
|
176
|
|
177
|
var old = aOldCookies.pop();
|
178
|
document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
|
179
|
aParts.join('/') + "/";
|
180
|
}
|
181
|
}
|
182
|
|
183
|
document.cookie = sFullCookie;
|
184
|
}
|
185
|
|
186
|
|
187
|
/**
|
188
|
* Read an old cookie to get a cookie with an old table state
|
189
|
* @param {string} sName name of the cookie to read
|
190
|
* @returns {string} contents of the cookie - or null if no cookie with that name found
|
191
|
* @memberof DataTable#oApi
|
192
|
*/
|
193
|
function _fnReadCookie ( sName )
|
194
|
{
|
195
|
var
|
196
|
aParts = window.location.pathname.split('/'),
|
197
|
sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
|
198
|
sCookieContents = document.cookie.split(';');
|
199
|
|
200
|
for( var i=0 ; i<sCookieContents.length ; i++ )
|
201
|
{
|
202
|
var c = sCookieContents[i];
|
203
|
|
204
|
while (c.charAt(0)==' ')
|
205
|
{
|
206
|
c = c.substring(1,c.length);
|
207
|
}
|
208
|
|
209
|
if (c.indexOf(sNameEQ) === 0)
|
210
|
{
|
211
|
return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
|
212
|
}
|
213
|
}
|
214
|
return null;
|
215
|
}
|
216
|
|