Making a useful JavaScript library SUPER-USEFUL!

Posted: March 26th, 2008 | Author: Joey | Filed under: Coding | 1 Comment »

Everyone likes (or should like) succinct-yet-readable code. Here is a technique you can use for taking your javascript modules and making them even more fun to use.

The following is a useful javascript module for getting and setting cookies. (It uses jQuery.) The usage is as straightforward as it gets. It provides three useful functions:

  1. Cookies.get(name);
  2. Cookies.set(name, value, [options]);
  3. Cookies.remove(name);

In addition, it provides the function Cookies.all() for debugging purposes.

var Cookies = {
 
  options :
    { path   : '/',
      expiry : null, // Days
      secure : (document.location.protocol == 'https:')
    },
 
  set :
    function (name, value, options) {
      var opts = {};
      jQuery.extend(opts, Cookies.options, options || {});
      options = opts;
 
      if (options.expiry) {
        // convert number of days from now to string
        options.expiry = new Date(
            new Date().getTime() + (options.expiry * 86400000)
        ).toGMTString();
      }
 
      // Build the cookie string
      document.cookie = name + '=' + value +
          ((options.expiry)? '; expires=' + options.expiry: '')
          + '; path=' + options.path + 
          ((options.secure)? '; secure=true': '');
    },
 
  get :
    function (name) {
      return $.trim($.grep(document.cookie.split(';'),
        function (cookie) {
          return $.trim(cookie).substring(0, name.length) == name;
        })[0] || name + '=').substring(name.length + 1);
    },
 
  remove :
    function (name) {
      return Cookies.set(name, "", -1);
    },
 
  all :
    function () {
      return document.cookie.split(';').map($.trim);
    }
 
}; // end Cookies

So what’s the big deal? The first weakness of this code is that the default options for setting a cookie are modifiable by the world. I don’t want your code changing settings for my code, nor mine for yours. This wouldn’t be too hard to fix by placing them as a local variable inside the set function. But what we’d really like is some sort of read-only access to those default options.

The second issue is more interesting. If you notice, there are four functions. And each of the functions takes a unique set of parameters. If this were Java, we could (but ought not to) implement this all with polymorphism. Sounds quite dumb, but bear with me. If the object Cookies were also a function, we could create a dispatcher and remove the need for explicit calls to the individual methods. Instead of Cookies.get('something'), we could just call Cookie('something'). Likewise for all the methods. Of course, you’d still be able to call the function by its full name. Let’s see it.

// Create a dispatcher
var Cookies = function (name, value, options) {
  // Case 1: no parameters supplied, dump the cookies.
  if (!name) {
    return Cookies.all();
 
  // Case 2: null value, delete cookie
  } else if (value === null) {
    return Cookies.remove(name);
 
  // Case 3: name supplied only, so get value
  } else if (value == undefined) {
    return Cookies.get(name);
 
  // Case 4: set a cookie with a value
  } else {
    return Cookies.set(name, value, options || {});
  }
 
}; // end dispatcher
 
$.extend(Cookies, (function () {
 
  // Create the private variables
  var defaults = {
    path   : '/',
    expiry : null, // Days
    secure : (document.location.protocol == 'https:')
  };
 
  // Create the public methods
  return {
    defaults : function () {
      return defaults;
    },
 
    set : function (name, value, options) {
      var opts = {};
      jQuery.extend(opts, defaults, options || {});
      options = opts;
 
      if (options.expiry) {
        // convert number of days from now to string
        options.expiry = new Date(
            new Date().getTime() + (options.expiry * 86400000)
        ).toGMTString();
      }
 
      // Build the cookie string
      document.cookie = name + '=' + value +
          ((options.expiry)? '; expires=' + options.expiry: '')
          + '; path=' + options.path + 
          ((options.secure)? '; secure=true': '');
    },
 
    get : function (name) {
      return $.trim($.grep(document.cookie.split(';'), 
        function (cookie) {
          return $.trim(cookie).substring(0, name.length) == name;
        })[0] || name + '=').substring(name.length + 1);
    },
 
    remove : function (name) {
      return Cookies.set(name, "", { expiry: -1});
    },
 
    all : function () {
      return document.cookie.split(';').map($.trim);
    }
  };
 
})());

The first thing you’ll notice is the dispatcher function. The does the simple logic for mapping the parameter combinations to the intended function. Then we extend the Cookies objects (remember, functions are just objects) with a new object. If you look, you’ll see that it is extended with a function that is immediately applied and returns an object. The advantage to doing this is that we can create closures, and encompass some “private” variables for those methods. Look at the defaults for an example of this. I added another function for inspecting the defaults, but you cannot modify them.

Now this library can be used as:

  • Cookies.get(name) or just Cookies(name)
  • Cookies.set(name, value, [options]) or just Cookies(name, value, [options])
  • Cookies.remove(name) or just Cookies(name, null)
  • Cookies.all() or just Cookies()
  • Cookies.defaults()

Hopefully this makes sense. If it gives you any good ideas, let me know.

Oh, and if you really were looking for a cookie library for javascript, you can download and use this (documented and commented) one if you have jQuery installed.

Download Javascript Cookies Version 1.0
Javascript Cookies (2.57 KB)

One Comment on “Making a useful JavaScript library SUPER-USEFUL!”

  1. 1 Hayden said at 6:07 pm on March 30th, 2008:

    SUPER-USEFUL!! Thanks!


Don't be shy...