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 |
} |