PDA

View Full Version : Adding cookie "remember" to this Javascript



Sartavius
10-03-2011, 05:13 AM
Okay, my javascript knowledge is slim at best so I'm wondering if someone would be so kind as to take a look at this:


function HideContent(d) {
document.getElementById(d).style.display = "none";
}
function ShowContent(d) {
document.getElementById(d).style.display = "block";
}
function ReverseDisplay(d) {
if(document.getElementById(d).style.display == "none") { document.getElementById(d).style.display = "block"; }
else { document.getElementById(d).style.display = "none"; }
}

As you can see it's just a simple show/hide DIV script and it's toggled on and off with:


<a href="javascript:ReverseDisplay('uniqueid)">Toggle On/Off</a>

I'm wondering if someone could show me how to add a cookie mechanism to this so that it will remember if the person had it set to on or off on a page reload or another visit. Probably remember indefinitely or a year; as the person can simply toggle it again to destroy the cookie if they change their mind.

I really hope this makes sense because at this late hour, I may not be articulating my predicament very well. :rolleyes:

Thanks in advance for any help/comments!!

jscheuer1
10-03-2011, 07:45 AM
A cookie is text data. So you can store the id(s) and/or display state(s) of your element(s) in one or more cookies. To figure out the most efficient method we need to know how many elements on the page could be toggled, and what their default (hard coded) display state(s) are, and if there's any unifying selector or parent element for them. But something very generic and less efficient can be written.

Ready made functions to set and read cookies will come in handy. Other cookie functions might also be useful. There are at least several such functions already available around the web. here are mine:

http://www.dynamicdrive.com/forums/blog.php?b=32

Also it's good to know that all browsers that accept cookies will run a function onunload if there is one to set them. All but Opera. And that the onunload function is required for efficiency in some browsers. So we have to branch for Opera. Or ignore it.

So we could have:


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<div id="one">One</div>
<div id="two">Two</div>
<a href="javascript:ReverseDisplay('one')">Toggle One On/Off</a>
<a href="javascript:ReverseDisplay('two')">Toggle Two On/Off</a>
<script type="text/javascript">
function HideContent(d) {
document.getElementById(d).style.display = "none";
cook.els[d] = 'none';
if(window.opera){cook.gather();}
}
function ShowContent(d) {
document.getElementById(d).style.display = "block";
cook.els[d] = 'block';
if(window.opera){cook.gather();}
}
function ReverseDisplay(d) {
if(document.getElementById(d).style.display == "none") { document.getElementById(d).style.display = "block"; cook.els[d] = 'block'; }
else { document.getElementById(d).style.display = "none"; cook.els[d] = 'none'; }
if(window.opera){cook.gather();}
}

var cook = {
set: function(n, v, d){ // cook.set takes (name, value, optional_persist_days) - defaults to session if no days specified
if(d){var dt = new Date();
dt.setDate(dt.getDate() + d);
d = '; expires=' + dt.toGMTString();}
document.cookie = n + '=' + escape(v) + (d || '') + '; path=/';
},
get: function(n){ // cook.get takes (name)
var c = document.cookie.match('(^|;)\x20*' + n + '=([^;]*)');
return c? unescape(c[2]) : null;
},
kill: function(n){ // cook.kill takes (name)
cook.set(n, '', -1);
},
killall: function(){ // cook.killall takes no parameters
var cookies = document.cookie.split(';'), i = cookies.length - 1;
for (i; i > -1; --i){
cook.kill(cookies[i].split('=')[0]);
}
},
els: {},
gather: function(){
var ar = [], p;
for(p in cook.els){
ar.push(p + ':' + cook.els[p]);
}
if(ar.length){
cook.set('the_elements', ar.join(','));
}
}
};

if(!window.opera){onunload = cook.gather;}

;(function(){
var str = cook.get('the_elements'), ar = [], el, the_el;
if(str){
ar = str.split(',');
for (var i = ar.length - 1; i > -1; --i){
el = ar[i].split(':');
if((the_el = document.getElementById(el[0]))){
the_el.style.display = el[1];
cook.els[el[0]] = el[1];
}
}
}
})();
</script>
</body>
</html>

There are a number of things I don't like about that code, still not perfect, but getting better:


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<div><a href="javascript:ReverseDisplay('one');">Toggle One On/Off</a></div>
<div id="one">One</div>
<div><a href="javascript:ReverseDisplay('two');">Toggle Two On/Off</a></div>
<div id="two">Two</div>
<script type="text/javascript">
;(function(){
var displayers = {
HideContent: function(d) {
document.getElementById(d).style.display = "none";
cook.els[d] = 'none';
if(window.opera){cook.gather();}
},
ShowContent: function(d) {
document.getElementById(d).style.display = "block";
cook.els[d] = 'block';
if(window.opera){cook.gather();}
},
ReverseDisplay: function(d) {
if(document.getElementById(d).style.display == "none") { document.getElementById(d).style.display = "block"; cook.els[d] = 'block'; }
else { document.getElementById(d).style.display = "none"; cook.els[d] = 'none'; }
if(window.opera){cook.gather();}
}
};

var cook = {
set: function(n, v, d){ // cook.set takes (name, value, optional_persist_days) - defaults to session if no days specified
if(d){var dt = new Date();
dt.setDate(dt.getDate() + d);
d = '; expires=' + dt.toGMTString();}
document.cookie = n + '=' + escape(v) + (d || '') + '; path=/';
},
get: function(n){ // cook.get takes (name)
var c = document.cookie.match('(^|;)\x20*' + n + '=([^;]*)');
return c? unescape(c[2]) : null;
},
kill: function(n){ // cook.kill takes (name)
cook.set(n, '', -1);
},
killall: function(){ // cook.killall takes no parameters
var cookies = document.cookie.split(';'), i = cookies.length - 1;
for (i; i > -1; --i){
cook.kill(cookies[i].split('=')[0]);
}
},
els: {},
gather: function(){
var ar = [], p;
for(p in cook.els){
ar.push(p + ':' + cook.els[p]);
}
if(ar.length){
cook.set('the_elements', ar.join(','));
}
},
addEvent: (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})()
};

if(!window.opera){cook.addEvent(window, 'unload', cook.gather);}

var a = document.getElementsByTagName('a'), re = /(ShowContent|HideContent|ReverseDisplay)\('(.+)'\)/, func, i;
for (i = a.length - 1; i > -1; --i){
if((func = re.exec(a[i].href))){
(function(el, func){
cook.addEvent(el, 'click', function(e){
e = e || event;
if(e.preventDefault){e.preventDefault();}
e.returnValue = false;
displayers[func[1]](func[2]);
return false;
});
})(a[i], func);
}
}

var str = cook.get('the_elements'), ar = [], el, the_el;
if(str){
ar = str.split(',');
for (i = ar.length - 1; i > -1; --i){
el = ar[i].split(':');
if((the_el = document.getElementById(el[0]))){
the_el.style.display = el[1];
cook.els[el[0]] = el[1];
}
}
}
})();
</script>
</body>
</html>

Sartavius
10-03-2011, 09:41 PM
Oddly enough, by using your second example of code it works fine when I C/P it straight out and test it.

But when I paste it into my own setup it doesn't work and the Firefox error console gives me the old "Error: ReverseDisplay is not defined Source File: javascript:ReverseDisplay('one');"

I'm stumped.

jscheuer1
10-03-2011, 10:21 PM
Paste it in or link to it.

Sartavius
10-03-2011, 10:38 PM
I think I've figured out the problem, but now I can't seem to set the expiration in your cookie function. It defaults to session if not set as you said, but WHERE in that code do you specify a number of days? lol

jscheuer1
10-04-2011, 01:35 AM
Find this function in the code:


gather: function(){
var ar = [], p;
for(p in cook.els){
ar.push(p + ':' + cook.els[p]);
}
if(ar.length){
cook.set('the_elements', ar.join(','));
}
},


For one day persistence:


cook.set('the_elements', ar.join(','), 1);

For one year:


cook.set('the_elements', ar.join(','), 365);

Or to be able to set it at the beginning of the code:


cook.set('the_elements', ar.join(','), persist);

And at the beginning:


;(function(){
var persist = 10; //set persistence in days (unquoted integer), or use '' (empty string) for session only
var displayers = {
HideContent: function(d) {
document.getElementById(d).style.display = "none";
cook.els[d] = 'none';
if(window. . . .

Sartavius
10-04-2011, 05:33 AM
Thanks for all the help! I'm thinking this might not be the route to go though after some playing. You see, I populate the name of the div (the one to be toggled on or off) with the php variable of the persons chat nickname. The problem is that the toggle on/off works fine and a cookie is stored but when I refresh the page (with a php function that receives new messages), it isn't remembering what I wanted to be toggled off for some reason.

Plus I'm thinking this method won't work because a cookie would have to be set for EACH nickname that another chatter might want to ignore. So if chatter A wanted to ignore chatters Bob, Sally and Frank...I think this method will only store one cookie and each subsequent person they wanted to ignore would just overwrite the prior cookie.

I suppose I will just have to go back to the drawing board and figure out a method to do this with PHP. Oh cruel world! hahaha.

Sartavius
10-04-2011, 05:34 AM
And on a side note, I love your cookie functions! Now that I understand how they're working it beats the heck out of most of the other ways I've seen to deal with cookies in Javascript. You're a true master!

jscheuer1
10-04-2011, 07:40 AM
I populate the name of the div (the one to be toggled on or off) with the php variable of the persons chat nickname. The problem is that the toggle on/off works fine and a cookie is stored but when I refresh the page (with a php function that receives new messages), it isn't remembering what I wanted to be toggled off for some reason.

This code doesn't work off of the name of the div. It works off of the id of the div. So - say you're PHP code is making something like:


<div name="Bob">whatever</div>

have it make instead:


<div name="Bob" id="Bob">whatever</div>


Plus I'm thinking this method won't work because a cookie would have to be set for EACH nickname that another chatter might want to ignore. So if chatter A wanted to ignore chatters Bob, Sally and Frank...I think this method will only store one cookie and each subsequent person they wanted to ignore would just overwrite the prior cookie.

It does make only one cookie, but that one cookie contains the id's and display states of all div's that were changed. And each time the page reloads, those stored preferences are added to the object that the cookie for next time will be made from. Unless changed, they will persist. If changed and only if changed, will the updated display state be used. Nothing is lost.

If you have this up live somewhere for testing, I'd be happy to have a look.

Oh and thanks for the vote of confidence on the cookie unit.

Sartavius
10-04-2011, 11:17 PM
If you have this up live somewhere for testing, I'd be happy to have a look.

Oh and thanks for the vote of confidence on the cookie unit.

That'd be great before I give up on this option entirely! I'll PM you the info you'll need to access the testing area.

davidd
12-06-2011, 10:44 AM
A cookie is text data. So you can store the id(s) and/or display state(s) of your element(s) in one or more cookies. To figure out the most efficient method we need to know how many elements on the page could be toggled, and what their default (hard coded) display state(s) are, and if there's any unifying selector or parent element for them. But something very generic and less efficient can be written.

Ready made functions to set and read cookies will come in handy. Other cookie functions might also be useful. There are at least several such functions already available around the web. here are mine:

http://www.dynamicdrive.com/forums/blog.php?b=32

Also it's good to know that all browsers that accept cookies will run a function onunload if there is one to set them. All but Opera. And that the onunload function is required for efficiency in some browsers. So we have to branch for Opera. Or ignore it.

So we could have:


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<div id="one">One</div>
<div id="two">Two</div>
<a href="javascript:ReverseDisplay('one')">Toggle One On/Off</a>
<a href="javascript:ReverseDisplay('two')">Toggle Two On/Off</a>
<script type="text/javascript">
function HideContent(d) {
document.getElementById(d).style.display = "none";
cook.els[d] = 'none';
if(window.opera){cook.gather();}
}
function ShowContent(d) {
document.getElementById(d).style.display = "block";
cook.els[d] = 'block';
if(window.opera){cook.gather();}
}
function ReverseDisplay(d) {
if(document.getElementById(d).style.display == "none") { document.getElementById(d).style.display = "block"; cook.els[d] = 'block'; }
else { document.getElementById(d).style.display = "none"; cook.els[d] = 'none'; }
if(window.opera){cook.gather();}
}

var cook = {
set: function(n, v, d){ // cook.set takes (name, value, optional_persist_days) - defaults to session if no days specified
if(d){var dt = new Date();
dt.setDate(dt.getDate() + d);
d = '; expires=' + dt.toGMTString();}
document.cookie = n + '=' + escape(v) + (d || '') + '; path=/';
},
get: function(n){ // cook.get takes (name)
var c = document.cookie.match('(^|;)\x20*' + n + '=([^;]*)');
return c? unescape(c[2]) : null;
},
kill: function(n){ // cook.kill takes (name)
cook.set(n, '', -1);
},
killall: function(){ // cook.killall takes no parameters
var cookies = document.cookie.split(';'), i = cookies.length - 1;
for (i; i > -1; --i){
cook.kill(cookies[i].split('=')[0]);
}
},
els: {},
gather: function(){
var ar = [], p;
for(p in cook.els){
ar.push(p + ':' + cook.els[p]);
}
if(ar.length){
cook.set('the_elements', ar.join(','));
}
}
};

if(!window.opera){onunload = cook.gather;}

;(function(){
var str = cook.get('the_elements'), ar = [], el, the_el;
if(str){
ar = str.split(',');
for (var i = ar.length - 1; i > -1; --i){
el = ar[i].split(':');
if((the_el = document.getElementById(el[0]))){
the_el.style.display = el[1];
cook.els[el[0]] = el[1];
}
}
}
})();
</script>
</body>
</html>

There are a number of things I don't like about that code, still not perfect, but getting better:


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

</head>
<body>
<div><a href="javascript:ReverseDisplay('one');">Toggle One On/Off</a></div>
<div id="one">One</div>
<div><a href="javascript:ReverseDisplay('two');">Toggle Two On/Off</a></div>
<div id="two">Two</div>
<script type="text/javascript">
;(function(){
var displayers = {
HideContent: function(d) {
document.getElementById(d).style.display = "none";
cook.els[d] = 'none';
if(window.opera){cook.gather();}
},
ShowContent: function(d) {
document.getElementById(d).style.display = "block";
cook.els[d] = 'block';
if(window.opera){cook.gather();}
},
ReverseDisplay: function(d) {
if(document.getElementById(d).style.display == "none") { document.getElementById(d).style.display = "block"; cook.els[d] = 'block'; }
else { document.getElementById(d).style.display = "none"; cook.els[d] = 'none'; }
if(window.opera){cook.gather();}
}
};

var cook = {
set: function(n, v, d){ // cook.set takes (name, value, optional_persist_days) - defaults to session if no days specified
if(d){var dt = new Date();
dt.setDate(dt.getDate() + d);
d = '; expires=' + dt.toGMTString();}
document.cookie = n + '=' + escape(v) + (d || '') + '; path=/';
},
get: function(n){ // cook.get takes (name)
var c = document.cookie.match('(^|;)\x20*' + n + '=([^;]*)');
return c? unescape(c[2]) : null;
},
kill: function(n){ // cook.kill takes (name)
cook.set(n, '', -1);
},
killall: function(){ // cook.killall takes no parameters
var cookies = document.cookie.split(';'), i = cookies.length - 1;
for (i; i > -1; --i){
cook.kill(cookies[i].split('=')[0]);
}
},
els: {},
gather: function(){
var ar = [], p;
for(p in cook.els){
ar.push(p + ':' + cook.els[p]);
}
if(ar.length){
cook.set('the_elements', ar.join(','));
}
},
addEvent: (function(){return window.addEventListener? function(el, ev, f){
el.addEventListener(ev, f, false);
}:window.attachEvent? function(el, ev, f){
el.attachEvent('on' + ev, f);
}:function(){return;};
})()
};

if(!window.opera){cook.addEvent(window, 'unload', cook.gather);}

var a = document.getElementsByTagName('a'), re = /(ShowContent|HideContent|ReverseDisplay)\('(.+)'\)/, func, i;
for (i = a.length - 1; i > -1; --i){
if((func = re.exec(a[i].href))){
(function(el, func){
cook.addEvent(el, 'click', function(e){
e = e || event;
if(e.preventDefault){e.preventDefault();}
e.returnValue = false;
displayers[func[1]](func[2]);
return false;
});
})(a[i], func);
}
}

var str = cook.get('the_elements'), ar = [], el, the_el;
if(str){
ar = str.split(',');
for (i = ar.length - 1; i > -1; --i){
el = ar[i].split(':');
if((the_el = document.getElementById(el[0]))){
the_el.style.display = el[1];
cook.els[el[0]] = el[1];
}
}
}
})();
</script>
</body>
</html>

Was looking for something that worked for a while and just came across this script.

The problem I had previously: When setting DIV to close it would still load up and then quickly disappear every page load (very unprofessional).

I tried yours and it works perfectly - Thank you so much! :D