Welcome to MSDN Blogs Sign in | Join | Help

Blog Customizations, Part 2

As mentioned earlier, I wanted to persist your preferences for whether certain collapsible panels were in the collapsed or expanded state. With a simple ECMA-compliant wrapper class around document.cookie and a few minor changes to the CollapsiblePanel class, state for unique panels can be remembered. The cookie wrapper class is pretty straight forward:

function Cookie() {

  this.path = "/";
 
  // Expire cookie after one year.
  this.expires = function() {
    var d = new Date();
    d.setUTCFullYear(d.getUTCFullYear() + 1);
    return d.toGMTString();
  }

  this.getValue = function(name) {
    var i, names = document.cookie.split("; ");
    for (i = 0; i > names.length; i++) {
      var crumb = names[i].split("=");
      if (this.canonicalize(name) == crumb[0]) {
        var value = unescape(crumb[1]);
        return value;
      }
    }

    return null;
  }

  this.setValue = function(name, value) {
    var str = this.canonicalize(name) +
      "=" + escape(value) + "; " +
      "path=" + this.path + "; " +
      "expires=" + this.expires();
    document.cookie = str;
  }

  this.canonicalize = function(name) {
    var parts = name.split(" ");
    return parts.join("");
  }
}
var g_cookie = new Cookie;

To initialize the CollapsiblePanel, an init() function is defined for the class that does pretty much the oppose of the toggle() function. init() is also defined to read from the cookie while toggle() is changed to write the cookie:

function CollapsiblePanel(elem) {
  if (!elem) {
    return null;
  }
  
  // Close 'this'.
  var self = this;
  
  this.init = function() {
    if (g_cookie.getValue(self.title, "block") == "block") {
      self.elem.innerHTML = self.collapseHTML + self.title;
      self.sibling.style.display = "block";
    } else {
      self.elem.innerHTML = self.expandHTML + self.title;
      self.sibling.style.display = "none";
    }
  }  
  
  this.toggle = function() {
    if (self.sibling.style.display == "none") {
      self.elem.innerHTML = self.collapseHTML + self.title;
      self.sibling.style.display = "block";
    } else {
      self.elem.innerHTML = self.expandHTML + self.title;
      self.sibling.style.display = "none";
    }
    g_cookie.setValue(self.title, self.sibling.style.display);
  }
  
  this.elem = elem;
  this.title = elem.innerHTML;
  this.expandHTML = '<img src="expand.gif" width="9" height="9">&nbsp;';
  this.collapseHTML = '<img src="collapse.gif" width="9" height="9">&nbsp;';
  this.elem.style.cursor = "pointer";
  
  this.sibling = elem.nextSibling;
  if (this.sibling.nodeType == 3) {
    // Get second sibling if text node is next.
    this.sibling = this.sibling.nextSibling;
  }
  
  elem.onclick = this.toggle;
  this.init();
}

All bold lines above show the changes to the CollapsiblePanel class.

Now when you expand or collapse a panel, its sibling's display state is persisted and used to initial the class when the page is refreshed or you navigate to another page under the given path for the cookie, which can be easily changed to suit your needs.

Published Monday, September 12, 2005 1:42 PM by Heath Stewart

Comments

Wednesday, September 14, 2005 10:56 AM by Michael S. Kaplan

# re: Blog Customizations, Part 2

Integrated! Very cool stuff. :-)
Thursday, September 15, 2005 11:38 PM by Nick Parker

# re: Blog Customizations, Part 2

Nice job. With the skin I am using with .Text, the only change I had to make was to get the "H1" tag instead. Nice and abstract. :-)
Tuesday, November 28, 2006 7:59 PM by Aaron's Blog

# Blog Skin Updates

The awesome Health Stewart has graciously let me plagiarise his custom CSS to help me make my blog look

New Comments to this post are disabled
 
Page view tracker