September 12th, 2005

Blog Customizations, Part 2

Heath Stewart
Principal Software Engineer

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.

Author

Heath Stewart
Principal Software Engineer

Heath is an application architect and developer, looking to help educate others to learn professional development. Besides designing and developing applications he enjoys writing about intermediate and advanced topics. Heath also consults for deployment packages and scenarios within Microsoft and for external customers.

0 comments

Discussion are closed.