Link to home
Start Free TrialLog in
Avatar of Scan_25
Scan_25

asked on

Javascript cookie for className's that =="shown"

I’m working on a menu script so what I got now is a script that is changing the class of an element on my page. I’ve got it working just the way I want it but now I’m having a hard time making a working cookie for it. I want to save all element with the class set to shown in the cookie. As I can’t use getElementByclassName I’m not sure how to pull this all together to save the ones that are set to shown. Any help would be great!

[code]
<style type="text/css">
.hidden {
      display:none;
}

.shown {
      display: block;
}
</style>
<script language="JavaScript" type="text/javascript">
function viewset(FieldID)
{
      layer = document.getElementById(FieldID);
      if (layer.className=="shown")
      {
            layer.className="hidden";
      }
      else
      {
            layer.className="shown";
      }
}
</script>
<body>
<a href="javascript:viewset('help1')">Help1</a><br />
<div class="hidden" id="help1">This is Help1!<br /></div>
<a href="javascript:viewset('help2')">Help2</a><br />
<div class="hidden" id="help2">This is Help2!<br /></div>
</body>
[/code]
Avatar of SnowFlake
SnowFlake
Flag of Israel image

there are a few ways you can go,
1) you can have a pre-ready list of id's and just scan throught them
    checking the value of className
2) you can just go over all the elements (using I think you can use getElementsByTagName('*')  or document.all in IE)

3) or scan elements recursively staring from a known parent element.

it all depelends on what you know about the structure of your menu.

also the above code fragment
     if (layer.className=="shown")
     {
          layer.className="hidden";
     }
     else
     {
          layer.className="shown";
     }

can be re-written
     layer.className=((layer.className=="shown")?"hidden":"shown");

SnowFlake
Avatar of Scan_25
Scan_25

ASKER

Well I would like to be able to NOT work from a pre list. I'm trying to come up with a way to get the elements by className. Your number two is what I've been trying but can't get to work right. Thanks for the short hand on that fragment. :)

Scan_25
Avatar of Scan_25

ASKER

If this helps this is what I've got trying to make and use the cookie now.

I think I have these two functions working right -

function readCookie(cname)
{
  var cookieValue = "";
  var search = cname + "=";
  if(document.cookie.length > 0)
  {
    offset = document.cookie.indexOf(search);
    if (offset != -1)
    {
      offset += search.length;
      end = document.cookie.indexOf(";", offset);
      if (end == -1) end = document.cookie.length;
      cookieValue = unescape(document.cookie.substring(offset, end))
    }
  }
  return cookieValue;
}

function getElementsByClassName(classname)
{
    var a = [];
    var re = new RegExp('\\b' + classname + '\\b');
    var els = document.all?document.all:document.getElementsByTagName("*");

    for(var i=0,j=els.length; i
        if(re.test(els[i].className))a.push(els[i]);
    return a;
}

now it this function I can't seem to get right

function writeCookie(cname)
{
        field = getElementsByClassName(shown);
        for (i=0; i <= field.length; i++)
        {
              if (field != null)
            openones = field + i
        }
  document.cookie=cname+"="+openones
}

But I don't understand how it needs to be written to the cookie so I’m sure that last function is all messed up.

Scan_25
function writeCookie(cname)
{
       field = getElementsByClassName(shown);
       for (i=0; i <= field.length; i++)
       {
            if (field != null)
          openones = field + i
       }
  document.cookie=cname+"="+openones
}

has a few errors in it:

1. assuming 'shown' is the actual class and not a variable with the class's name in it
the line
       field = getElementsByClassName(shown);
should have been
       field = getElementsByClassName('shown');

you can verify that by adding
alert(field.length);
in the line after it.

2.because field is an array of ELEMENTS (not IDs) as can be seen from:
   if(re.test(els[i].className))a.push(els[i]);
   you can not store them directly in the cookie.
   you can store thair IDs or Indai.
   
   this calls for some thinking:
   a. how will you later restore it ?
   b. what happens if the list of such elements in the page changes between save and restore.

  It is my oppinion that both Q's lead to the conclusion that you should use an ID for any such element
  and the its the ID's that should be stored.
  (which will also make restoring them more efficiant).

also note that  
   for(var i=0,j=els.length; i
        if(re.test(els[i].className))a.push(els[i]);
 
seems to be missing a ++)
SnowFlake.

Avatar of Scan_25

ASKER

I am using an ID as is but I want to be able to add to the easily. I don’t want to have the ID hard coded in the javascript. In my first viewset function I change the class by the ID then I want to save all id’s that have there class set to shown in the cookie. I guess it’s best to save the cookie with the window.onunload command then remove the cookie with something like window.close. You see I would like to save the ID’s class settings just for the visit. Your right it is missing the ++) sorry. I also want to say thanks for your help on this your really great.

--
Scan_25
you got me a bit confused with the whole window.close issue.
accress what event do you want to save the cookie ?
are you trying to do a "client side session cookie" namely maintain the cookie
only while its the same window even if the page navigates but clear it if the window is closed
and the reopened.

I can think of two approaches to this:
1) use expando properties of the window object ( has to be tested )
2) use a cookie with a short lifespan (say 1 min.)
    which you write onunload and read onload
    this will work as long as you don't leave pages that are aware of this cookie
    for more then that duration. but will also go across windows if you have a
    few open at the same time or close and open a new window withing the 1 min. period.

I think the first one is much better then the second. I will play with it and post soon.

have you got the extraction of the ID's to work ?
or do you still need help with that code as well ?

SnowFlake.

Avatar of Scan_25

ASKER

This is the java I have now to make and read the cookie but I’m just not smart enough to make it work.
function readCookie(cname)
{
  var cookieValue = "";
  var search = cname + "=";
  if(document.cookie.length > 0)
  {
    offset = document.cookie.indexOf(search);
    if (offset != -1)
    {
      offset += search.length;
      end = document.cookie.indexOf(";", offset);
      if (end == -1) end = document.cookie.length;
      cookieValue = unescape(document.cookie.substring(offset, end))
    }
  }
  return cookieValue;
}

function getElementsByClassName(classname)
{
    var a = [];
    var re = new RegExp('\\b' + classname + '\\b');
    var els = document.all?document.all:document.getElementsById("*");

    for(var n=0; n <= els.length; n++)
    {
        if(re.test(els[n].className))a.push(els[n]);
    }
    return a;
}

function writeCookie(cname)
{
      field = getElementsByClassName('shown');
      for (i=0; i <= field.length; i++)
      {
      if (field != null)
            openones = field + i;
      }
  document.cookie=cname+"="+openones
}

window.onunload=writeCookie(savethis)

*/ I really think I’m getting this all wrong but it’s ok I’m looking in to a brain transplant soon. ;) /*

if (readCookie(savethis) != '')
{
    var els = document.all?document.all:document.getElementsById("*")
      for (x=0; x<els.length; x++)
      {
            idarray[c]=els[x]
            c++;
      }

    var openresults=get_cookie(savethis).split(" ")
      for (i=0 ; i <= openresults.length ; i++)
      {
                idarray[openresults[i]].className="shown";
      }
}


Scan_25

thanks for your help and I'll up the points some more as I didn't know how far off I was.
SOLUTION
Avatar of SnowFlake
SnowFlake
Flag of Israel image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Scan_25

ASKER

with your code it doen't seem to be making the cookie i just keep getting resoring null and the error in explorer is strIDs is null or an object. I'll also show you what i have now after your changes.

<style type="text/css">
.hidden {
     display:none;
}

.shown {
     display: block;
}
</style>

<script language="JavaScript" type="text/javascript">
function viewset(FieldID)
{
     layer = document.getElementById(FieldID);
     layer.className=((layer.className=="shown")?"hidden":"shown");
}
</script>

<body>
<a href="javascript:viewset('help1')">Help1</a><br />
<div class="hidden" id="help1">This is Help1!<br /></div>
<a href="javascript:viewset('help2')">Help2</a><br />
<div class="hidden" id="help2">This is Help2!<br /></div>

<script language="JavaScript" type="text/JavaScript">
var strIDs=getCookie('savethis');
alert('restoring ' + strIDs); // this is to see what is about to be written and
                                      // can be removed when working o.k.
if (strIDs!='') {
   arrIds=strIDs.split(',');
   for (var i=0;i <= arrIds.length ; i++) {
      id=arrIds[i];
      el=document.getElementById(id);
      if (el) {
          // the following is better then
          // el.className='shown';
          // because it also handles elements that have multiple classes.
          el.className=el.className.replace('shown','');
          el.className=el.className + ' shown';
      }
   }
}

function setCookie(name, value, expires, path, domain, secure) {
  var curCookie = name + "=" + escape(value) +
      ((expires) ? "; expires=" + expires.toGMTString() : "") +
      ((path) ? "; path=" + path : "") +
      ((domain) ? "; domain=" + domain : "") +
      ((secure) ? "; secure" : "");
  document.cookie = curCookie;
}

function getCookie(name) {
  var dc = document.cookie;
  var prefix = name + "=";
  var begin = dc.indexOf("; " + prefix);
  if (begin == -1) {
    begin = dc.indexOf(prefix);
    if (begin != 0) return null;
  } else
    begin += 2;
  var end = document.cookie.indexOf(";", begin);
  if (end == -1)
    end = dc.length;
  return unescape(dc.substring(begin + prefix.length, end));
}

function getIdsOfElements(els){
    ids=[];
    for (var i=0; i<els.length; i++)
     {
          ids[i]=els[i].id;
     }
     return ids;
}

function getElementsByClassName(classname)
{
    var a = [];
    var re = new RegExp('\\b' + classname + '\\b');
    var els = document.all?document.all:document.getElementsById("*");

    for(var n=0; n <= els.length; n++)
    {
        if(re.test(els[n].className))a.push(els[n]);
    }
    return a;
}

window.onunload=function(){
      var els= getElementsByClassName('shown');
      var ids= getIdsOfElements(els);
      var strIDs =  ids.join(','); // to transform the array of ids to a comma separated string of ids
      alert('storing ' + strIDs); // this is to see what is about to be written and
                                            // can be removed when working o.k.
      setCookie('savethis',strIDs)
}
</script>
</body>


Did I miss anything?
no, you didn't - I did.

two changes are required:

1)

change
if (strIDs!='') {
to
if (strIDs && (strIDs!='')) {

and in getElementsByClassName
change the for loop from:
for(var n=0; n <= els.length; n++)
to
for(var n=0; n < els.length; n++)

and at least on my computer it then works.

SnowFlake
Avatar of Scan_25

ASKER

Now I have it restoring and storing the right stuff but it's not setting the class back to shown. Any idea's we are so that I can taste it. If change the
          el.className=el.className + ' shown';
to
          el.className= 'shown';

it works but I like the idea of multiple classes..

scan_25
Avatar of Scan_25

ASKER

It also doesn't seem to work with firefox is there any hope?
Avatar of Scan_25

ASKER

I changed this
         el.className=el.className.replace('shown','');
          el.className=el.className + ' shown';

to this
         el.className=el.className.replace('hidden','shown');
          el.className=el.className + ' shown';

and it works in IE but I would like it to work in Firefox also. I can't even find the cookie in firefox so it seems as if it doesn't make it.

Scan_25
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Scan_25

ASKER

You know I had that by TagName and was as dumb to change it without you saying to. I'm sorry about that.

you so rock my little world.. LOL

We have just made a nice little simple menu system that is very easy to work with and runs on IE, Firefox and many others.

Well I guess I'll keep my own brain after all :)

Scan_25
your welcome, thanks for the grade and points.
SnowFlake