JQuery for Everyone: Cookies and Plugins
JQuery plugin patterns are great. The recommended pattern allows for an options object to pass into the methods during invocation with a bunch of defaults to make options, well, optional.
But options don’t play well with cookies. In this article, I’ll tell you a little about why options are great, why you might want to store them in a cookie, and how to do that using SharePoint’s built-in functions.
Building Options with $.extend()
One jQuery utility in particular makes this simple to build. The $.extend() function allows you to merge multiple objects. Let’s say we’re making a cool new jQuery method to color-code SharePoint calendar items. We’ll start with a template like this:
<script type="text/javascript"> (function(){ jQuery.fn.colorCal = function(options){ //do something } })(); </script>
We’re telling the browser we want to add a method to the jQuery object using prototype (we’re using the .fn notation as an alias but it means the same thing).
Try this: Open Firebug to a page with jQuery on it (or use the jQueryify bookmarklet). Type “jQuery” into your console window. What was returned? Now type jQuery(). Did you see a difference?
To make use of options (or to just leave a placeholder for future functionality) we add this:
<script type="text/javascript"> (function(){ var defaults = { 'background-color': 'red' }; jQuery.fn.colorCal = function(options){ opts = $.extend({},defaults,options); //do something with opts } })(); </script>
We created a new variable called defaults. Since it’s inside our closure, only colorCal() will have access to it. We then create the variable opts which combines (in order) an empty set, defaults, and any options. The order is important since later parameters with the same name will overwrite the previous ones.
Try this: Open Firebug on a page with jQuery loaded. Create a global object by typing: myObj = {test: “1″} and clicking Run. Call your object with myObj, myObj.test, and myObj['test']. Now extend your object with this: $.extend({test:”2″},myObj,{test:”3″, anothertest:”1″}) and click Run. Try to call your object again, what happened to the value of the test parameter?
Using Options
To actually make this work, and understand how options make things awesome, let’s put some code in the function where it says “do something.”
<script type="text/javascript"> (function(){ var defaults = { 'background-color': 'red' }; jQuery.fn.colorCal = function(options){ opts = $.extend({},defaults,options); this.each(function(i,e){ //using this $(e).css(opts); //using e, a single object in this console.log(stringObj(opts)); }); }; })(); </script>
If you recall from the previous article, this refers to the objects collected by the $() function. There could be one or more than one DOM object in that array, so we use the .each() method to iterate over them doing something–in this case, applying the opts parameter to the element’s CSS.
Note: You can run that function in your Firebug console without the script tags. Remember when setting parameters in object notation, if the parameter has a character like “-” you have to put the parameter in quotes.
Try this: Put the above function on a default Calendar view (monthly) page with jQuery using a CEWP or run everything from Firebug. Now start using your custom method: $(”td.ms-cal-noworkitem”).colorCal(); Did anything change? Try these commands next: $(”td.ms-cal-noworkitem”).colorCal({’background-color’:'black’}); $(”td.ms-cal-topday”).colorCal({’text-align’:'center’}); Did you guess what was going to happen before it happened?
Saving Options With Cookies
Ok, let’s pretend that someone uses this method to create some links on a Calendar to highlight specific days of the month. If you drill down into the day view then come back to the month view, the links must be clicked again. Users might expect their preferences to be stored (at least for the current browser session).
The challenge is that cookies only store strings, not objects. So we need to add a function to our solution that can do that for us.
<script type="text/javascript"> (function(){ var stringObj = function(obj){ var str = "{"; var len=0; for (var name in obj){ if (obj.hasOwnProperty(name)){ len++; str += (len>1)?',':""; str += name+':"'+ obj[name]+'"'; } } str += "}"; return(str); }, defaults = { 'background-color': 'red' }; jQuery.fn.colorCal = function(options){ opts = $.extend({},defaults,options); console.log(stringObj(opts)); //watch the options come back as a string this.each(function(i,e){ $(e).css(opts); }); }; })(); </script>
Try This: the stringObj() function is a private variable. Open Firebug console and try to call it with stringObj or stringObj() and click Run. Type $() and click Run. Find colorCal in the list of methods, do you see stringObj() there?
We can make use of the built-in SharePoint function, SetCookie() to create a cookie for the current session. But there’s a trap, the equal sign. When the browser sees “=” in a cookie string, it thinks you’re done with the string. So, we need to use a RegEx replace to swap = for something else. I use ~ but you can use whatever, just be consistent because you will need to decode it when you read the cookie. I tried using other entity references but the parser always saw an “=” underneath and broke my cookies.
SetCookie("cookie_name",stringObj(o).replace(/\=/g,"~"), "/");
Note: for help on regular expressions, I recommend the RegExr adobe AIR app.
When we want to retrieve our cookie (like on the document.ready event) we use something like this:
var g = GetCookie("cookie_name");
Only, now we have to convert that string into an object. Here’s where you may digress into factions. I use eval(). Per the JavaScript authorities on this planet, eval() is evil. There are other parsers to convert strings into object literals (mainly because of JSON). But I’d rather use the eval() shortcut as I think the risks to browser security in this situation are very low.
... getOptions = function(str){ if (str.indexOf("{")===0){ return eval('('+str+')'); } }, ...
getOptions, another private variable, will make sure the first character is a curly brace then try to evaluate the string, which converts a string in object notation into an object.
To call our custom method with the cookie’s options we have do something like:
getOptions(g.replace(/\~/g,"=").replace(/([^,|"|'])\s/g,"$1%20"));
The second .replace() method is for yet another trap. Sometimes, when converting things like URLs, whitespace is preserved when you want to use it as %20. This expression only allows whitespace at the beginning of a value segment to remain.
- JQuery for Everyone: Accordion Left Nav
- JQuery for Everyone: Print (Any) Web Part
- JQuery for Everyone: HTML Calculated Column
- JQuery for Everyone: Dressing-up Links Pt1
- JQuery for Everyone: Dressing-up Links Pt2
- JQuery for Everyone: Dressing-up Links Pt3
- JQuery for Everyone: Cleaning Windows Pt1
- JQuery for Everyone: Cleaning Windows Pt2
- JQuery for Everyone: Fixing the Gantt View
- JQuery for Everyone: Dynamically Sizing Excel Web Parts
- JQuery for Everyone: Manually Resizing Web Parts
- JQuery for Everyone: Total Calculated Columns
- JQuery for Everyone: Total of Time Differences
- JQuery for Everyone: Fixing Configured Web Part Height
- JQuery for Everyone: Expand/Collapse All Groups
- JQuery for Everyone: Preview Pane for Multiple Lists
- JQuery for Everyone: Preview Pane for Calendar View
- JQuery for Everyone: Degrading Dynamic Script Loader
- JQuery for Everyone: Force Checkout
- JQuery for Everyone: Replacing [Today]
- JQuery for Everyone: Whether They Want It Or Not
- JQuery for Everyone: Linking the Attachment Icon
- JQuery for Everyone: Aspect-Oriented Programming with jQuery
- JQuery for Everyone: AOP in Action - loadTip Gone Wild
- JQuery for Everyone: Wiki Outbound Links
- JQuery for Everyone: Collapse Text in List View
- JQuery for Everyone: AOP in Action - Clone List Header
- JQuery for Everyone: $.grep and calcHTML Revisited
- JQuery for Everyone: Evolution of the Preview
- JQuery for Everyone: Create a Client-Side Object Model
- JQuery for Everyone: Print (Any) Web Part(s) Plugin
- JQuery for Everyone: Minimal AOP and Elegant Modularity
- JQuery for Everyone: Cookies and Plugins
- JQuery for Everyone: Live Events vs. AOP
- JQuery for Everyone: Live Preview Pane
- JQuery for Everyone: Pre-populate Form Fields
- JQuery for Everyone: Get XML List Data with OWSSVR.DLL (RPC)
- Use Firebug in IE
- JQuery for Everyone: Extending OWS API for Calculated Columns
- JQuery for Everyone: Accordion Left-nav with Cookies Speed Test
- JQuery for Everyone: Email a List of People with OWS
- JQuery for Everyone: Faster than Document.Ready
- jQuery for Everyone: Collapse or Prepopulate Form Fields
- jQuery for Everyone: Hourly Summary Web Part
- jQuery for Everyone: "Read More..." On a Blog Site
- jQuery for Everyone: Slick Speed Test
- jQuery for Everyone: The SharePoint Game Changer
- JQuery For Everyone: Live LoadTip