Blog Customizations, Part 2

Blog Customizations, Part 2

  • Comments 3

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.

Leave a Comment
  • Please add 7 and 2 and type the answer here:
  • Post
  • Integrated! Very cool stuff. :-)
  • 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. :-)
  • The awesome Health Stewart has graciously let me plagiarise his custom CSS to help me make my blog look

Page 1 of 1 (3 items)