PDA

View Full Version : Cookie script to LocalStorage?



pxlcreations
07-07-2010, 02:15 PM
Hello all, I need some help here. I'm new to HTML 5 and I'm not sure how to convert my cookie script over to HTML 5 LocalStorage. If anyone could help, I would appreciate it greatly.

Here's my cookie script:


var currentRotation=null;

function checkOrientAndLocation(){
if(currentRotation != window.orientation){
setOrientation();
}
}

function setOrientation(){
switch(window.orientation){
case 0:
orient = 'portrait';
break;
case 90:
orient = 'landscape';
break;
case -90:
orient = 'landscape';
break;
}
currentRotation = window.orientation;
document.body.setAttribute("orient",orient);
setTimeout(scrollTo,0,0,1);
}

$(window).unload(function() { // On page unload
$('.remember').each(function() { // Save each value to expire in a year
$.cookie(this.id, this.value, {expires: 365});
});
$('.draggable').each(function() { // Save draggable positions
var draggable = $(this);
$.cookie(this.id, draggable.css('top') + '_' + draggable.css('left'), {expires: 365});
$.cookie('disp' + this.id, draggable.css('display'), {expires: 365});
});
});

$(function() {
var val, pos, disp;
setInterval(checkOrientAndLocation,1000);
$('.remember').each(function() {
var val = $.cookie(this.id); // Retrieve value for this element
if (val) {
this.value = val;
}
}
);
$('.draggable').each(function() {
var pos = $.cookie(this.id); // Retrieve values for this element
if (pos) {
pos = pos.split('_');
$(this).css({position: 'absolute', top: pos[0], left: pos[1]});
}
var disp = $.cookie('disp' + this.id);
if (disp) {
this.style.display = disp;
}
}
).touch({animate: false, sticky: false, dragx: true, dragy: true,
rotate: false, resort: false, scale: false
});
});

jscheuer1
07-07-2010, 03:46 PM
This cannot be tested locally. The page must be live or on a local server like wamp, xamp, etc.


var currentRotation=null;

function checkOrientAndLocation(){
if(currentRotation != window.orientation){
setOrientation();
}
}

function setOrientation(){
switch(window.orientation){
case 0:
orient = 'portrait';
break;
case 90:
orient = 'landscape';
break;
case -90:
orient = 'landscape';
break;
}
currentRotation = window.orientation;
document.body.setAttribute("orient",orient);
setTimeout(scrollTo,0,0,1);
}

$(window).unload(function() { // On page unload
$('.remember').each(function() { // Save each value to expire only when removed/reset
localStorage.setItem(this.id, this.value);
});
$('.draggable').each(function() { // Save draggable positions
var draggable = $(this);
localStorage.setItem(this.id, draggable.css('top') + '_' + draggable.css('left'));
localStorage.setItem('disp' + this.id, draggable.css('display'));
});
});

$(function() {
var val, pos, disp;
setInterval(checkOrientAndLocation,1000);
$('.remember').each(function() {
var val = localStorage.getItem(this.id); // Retrieve value for this element
if (val) {
this.value = val;
}
}
);
$('.draggable').each(function() {
var pos = localStorage.getItem(this.id); // Retrieve values for this element
if (pos) {
pos = pos.split('_');
$(this).css({position: 'absolute', top: pos[0], left: pos[1]});
}
var disp = localStorage.getItem('disp' + this.id);
if (disp) {
this.style.display = disp;
}
}
).touch({animate: false, sticky: false, dragx: true, dragy: true,
rotate: false, resort: false, scale: false
});
});

Notes: The persistence for localStorage cannot be set. It's forever or until the item is cleared or set to a different value.

In Firefox and IE (probably others), unlike with cookies, this cannot be tested locally. The page must be live or on a local server like wamp, xamp, etc.

pxlcreations
07-07-2010, 04:29 PM
Thank you! I just had to change "absolute" to "relative" for the CSS to work, but otherwise it is exactly what I needed.

pxlcreations
07-07-2010, 05:38 PM
Ok, let me be a little more clear. This has to work on the iPad and here's what's happening on there that doesn't work on a regular browser:

- When you make a change with the divs, the localstorage isn't getting updated so when you reload the page everything is not like it was before.

So somewhere in that script, Mobile Safari isn't seeing the changes that are made when a div is moved or hidden.

I'm sorry this isn't working, you can't see what's happening unless you view it on an iPad, but I will try and explain everything simply.

jscheuer1
07-07-2010, 06:44 PM
Remember, the page must be live.

I only did what you asked. That is the w3c approved syntax for localStorage and works in browsers that support that standard and have it enabled.

Perhaps it isn't supported on iPad. After all, localStorage can fill up the hard drive pretty quickly if it's small hard drive. To test that use a script on a plain page:


<script type="text/javascript">
alert(typeof localStorage);
</script>

It should come back:

object

not null or undefined.

If that's OK, make sure it's firing onunload:


<script type="text/javascript">
alert(typeof onunload);
</script>

same deal, should be object.

If both of these are OK -

Since you are using touch to move things around, make sure this is accomplished by actually changing the css values you are later storing in localStorage.

Check to see that the values stored in localStorage are those expected, for example:


$(function() {
var val, pos, disp;
setInterval(checkOrientAndLocation,1000);
$('.remember').each(function() {
var val = localStorage.getItem(this.id); // Retrieve value for this element
if (val) {
alert(val);
this.value = val;
}
}
);
$('.draggable').each(function() {
var pos = localStorage.getItem(this.id); // Retrieve values for this element
if (pos) {
alert(pos);
pos = pos.split('_');
$(this).css({position: 'absolute', top: pos[0], left: pos[1]});
}
var disp = localStorage.getItem('disp' + this.id);
if (disp) {
alert(disp);
this.style.display = disp;
}
}
).touch({animate: false, sticky: false, dragx: true, dragy: true,
rotate: false, resort: false, scale: false
});
});

pxlcreations
07-07-2010, 07:04 PM
Ok, both come back as object which is good...

Then I tested the second one and I get alerts saying things like:

block
none
auto_auto (??)
210.5px_135px

The block and none make sense, but the others don't.

jscheuer1
07-07-2010, 07:05 PM
I was just playing with Safari Win, and it appears to have a bug as regards localStorage. The values aren't always retrieved. Refreshing the page more than once or setting a timeout after the initial query to make it again may be required under some circumstances. I tried 100ms, it was too short. 3000ms worked OK, but would be a bit long. What this value must be may vary depending upon connection speed/bandwidth. It's obviously a bug in Safari.

If the iPad supports cookies, I'd stick with them. If it doesn't, it's unlikely to support localStorage. But if the tests from my previous post show that it does, a timeout may be your answer if the iPad's Safari has the same bug as Safari Win, at least until this bug is fixed.

pxlcreations
07-07-2010, 07:14 PM
Ok, so what would I do to fix the bug?

Also, I would rather use cookies since the script I have works, but I want to set the expiration date for 1 year or more but so far it's not working. Would you mind taking a look at it?

(Sorry about the 2 posts)

jscheuer1
07-07-2010, 08:48 PM
Well we could play around with setTimeout to see what the optimal delay might be and hope that it's constant over varying bandwidths and connection speeds. If we delay the first try until page load, rather than domready as your current script does, that might have a better chance of working. But I'm skeptical because one of the 'improvements' of localStorage over cookies is that they are not headers. This I imagine means that the server must ask the browser for them in real time. If so, the delay would be between the time of the first request and the second request, regardless of when the first request is made.

That could work to our advantage if we asked for them as the page was loading, and then again after it was loaded, but only if that represents enough of a delay.

The only ones who can really fix this bug are the browser's developers. I'm imagining that in Safari the request is being made asynchronously when it should be made synchronously.

However, this might only be a bug in Safari Win.

As to reverting to cookies, unless there is something about the browser that prevents cookies being set for the period time you desire, you are either using the cookie code incorrectly, or it's not written correctly. From looking at your code I assume you are using some sort of jQuery cookie plugin, right? Which one, where did you get it?

Oh, and we cross posted on the last go round. Those values look correct to me, auto_auto would mean that the top and left styles hadn't been set yet, and 210.5px_135px looks reasonable, if that's what they were set to.

pxlcreations
07-07-2010, 08:59 PM
Ok, I see what you mean there. I think I'd rather go with the cookie script only because it has most of the kinks worked out already where as the LocalStorage is going to need some more modifications.

You are also correct that it is a jQuery script, so the script setting the cookies is here:


var currentRotation=null;

function checkOrientAndLocation(){
if(currentRotation != window.orientation){
setOrientation();
}
}

function setOrientation(){
switch(window.orientation){
case 0:
orient = 'portrait';
break;
case 90:
orient = 'landscape';
break;
case -90:
orient = 'landscape';
break;
}
currentRotation = window.orientation;
document.body.setAttribute("orient",orient);
setTimeout(scrollTo,0,0,1);
}

$(window).unload(function() { // On page unload
$('.remember').each(function() { // Save each value to expire in a year
$.cookie(this.id, this.value, {expires: 365});
});
$('.draggable').each(function() { // Save draggable positions
var draggable = $(this);
$.cookie(this.id, draggable.css('top') + '_' + draggable.css('left'), {expires: 365});
$.cookie('disp' + this.id, draggable.css('display'), {expires: 365});
});
});

$(function() {
var val, pos, disp;
setInterval(checkOrientAndLocation,1000);
$('.remember').each(function() {
var val = $.cookie(this.id); // Retrieve value for this element
if (val) {
this.value = val;
}
}
);
$('.draggable').each(function() {
var pos = $.cookie(this.id); // Retrieve values for this element
if (pos) {
pos = pos.split('_');
$(this).css({position: 'absolute', top: pos[0], left: pos[1]});
}
var disp = $.cookie('disp' + this.id);
if (disp) {
this.style.display = disp;
}
}
).touch({animate: false, sticky: false, dragx: true, dragy: true,
rotate: false, resort: false, scale: false
});
});

And the jQuery cookie script is:


/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/

/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
* used when the cookie was set.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie and will not be retained
* when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
* require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/

/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// CAUTION: Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
};

I want the expiration date set for a year, where as this seems to be only setting it for the session:

http://i46.tinypic.com/2nosjc.png

jscheuer1
07-07-2010, 10:51 PM
In Safari Win, you can look at the cookies by clicking:

edit > preferences > security > view cookies

If your browser on iPad has that or an equivalent, do that. Find one of your cookies and check the expires date. If it's as expected, there's a bug in the browser or it's set to only hold a limited number of cookies. Even if it's expires is not set as expected there might still be a bug in the browser. But there might also or instead be a problem with the cookie setting code.

I looked it over a little (I can still look at it further), it uses the toUTCString method. The toGMTString method is/was preferred, but I don't think there is any real difference, though there might be.

See if you can find out that information, whether the expires date is set as expected or not.

pxlcreations
07-07-2010, 10:52 PM
Yeah, I've been checking the expire date on my Mac Safari and it still sets it to end at the end of the day. I don't know why, but I'm pretty sure it is not a browser bug, but instead a bug in the script. I'll change the UTC to GMT and see what happens.

Well would you look at that, changing it to toGMTString makes it set a year ahead! Perfect! Thank you once again, I don't think anyone else would've found that.

jscheuer1
07-08-2010, 03:39 AM
That's pretty bizarre. I say because if I do:


<script type="text/javascript">
var d = new Date();
alert(d.toUTCString() === d.toGMTString());
</script>

in any browser (including Safari Win) I have, it alerts true.

But I suppose it's possible that on the iPad it might be false.

Try it and see.

If it is false, I'd be interested in the difference. So then do:


<script type="text/javascript">
var d = new Date();
alert('UTC = ' + d.toUTCString() + '\nGMT = ' + d.toGMTString());
</script>

and see if you can spot the difference.

Added Later:

If there is no difference, then the script was OK as it was, just some caching issue going on. However, just to be on the safe side, stick with GMT.

pxlcreations
07-10-2010, 02:20 PM
Yeah, I still don't know why, but now the cookie menu in safari and firefox show that they will expire in 2011, so its working fine now.

On a side note, is there a way I could have a link that would clear all the cookies from the site?

jscheuer1
07-10-2010, 03:19 PM
I haven't tested either of these, but they should work (except perhaps for secure cookies, which yours are not) -

To kill the cookies you have:


funtion killCookies(){
$('.remember').each(function() {
$.cookie(this.id, '', {expires: -1});
});
$('.draggable').each(function() {
var draggable = $(this);
$.cookie(this.id, '', {expires: -1});
$.cookie('disp' + this.id, '', {expires: -1});
});
}

To kill all cookies on a page:


function killAllCookies(){
var cookies = document.cookie.split(';'), i = cookies.length - 1;
for (i; i > -1; --i){
$.cookie(cookies[i].split('=')[0], '', {expires: -1});
}
}

Just be aware though, if you run either of these while the page is loaded, and then unload the page, new cookies will be set.

pxlcreations
07-10-2010, 03:41 PM
Ok, I set up the link and it's deleting the cookies, but when I reload the page they just come back, which is what you were saying here:


Just be aware though, if you run either of these while the page is loaded, and then unload the page, new cookies will be set.

Are there any ways to get around that?

jscheuer1
07-10-2010, 05:16 PM
To do that you have to remove the unload code. You can do that at least two ways:



$(window).unbind('unload');

Which you could put at the start of either of the two kill functions from my last post.



Or you could simply temporarily comment out the unload code from your script.

pxlcreations
07-10-2010, 05:37 PM
To do that you have to remove the unload code. You can do that at least two ways:



$(window).unbind('unload');

Which you could put at the start of either of the two kill functions from my last post.



Or you could simply temporarily comment out the unload code from your script.



Works perfect! Thank you for all the help on this, is it ok if I PM you if I have any more questions?

jscheuer1
07-10-2010, 08:24 PM
Works perfect! Thank you for all the help on this, is it ok if I PM you if I have any more questions?

You're welcome. I like to reserve PM's for stuff that shouldn't be in the open forum, like links to pages you don't want indexed from the forum here. But for general ans specific help stuff I like it to be in the open forum where there are more liberal limits on the amount of text per message, attachments (no attachments in PM's), and others can learn from it too.

pxlcreations
07-10-2010, 09:26 PM
Ok, that's fine. So in that other post about positioning the Divs in the center of the screen, that was a result of having to change the "relative" to "absolute" in the cookie file. When it's set at "relative" and the page is reloaded, the divs are in totally different positions on the screen.

So do you know how to make the remembered positions correct if I were to use relative?