Friday 7 October 2011

SharePoint 2007 colour (color) calendar

The in-built calendar view is SharePoint 2007 is a heck of a lot better than the one in 2003 but it still lacks a feature requested by many customers - the ability to colour (or color for our US friends) code the entries like you can in Outlook.

In SharePoint 2003 the calendar was rendered entirely using Javascript so it was a question of modifying the schema.xml file for the list to output the relevant parameters and then overiding an ows.js function to ensure the colours got rendered. However in 2007 the calendar view is generated from code, specifically a bunch if classes like SPListView, SPCalendarView etc. Lots of this class heirarchy is marked as sealed or internal so it is not easy to try to inherit and change the behaviour. Plus lots of the code is obfuscated too.

First of all I created a standard SharePoint Calendar list. Then I added a Choice column called Category and put the following values in the choice field.

Appointment
Birthday
Business
Important
Vacation




Secondly I created a calculated column called CatTitle set to the following formula as seen in the image,

=Category & "|||" & Title

You could make these site columns if you wish to re-use elsewhere.



Finally change the calendar view on the list so that the display field for each of day/week/month view is the CatTitle field.



Now we need to insert some javascript to edit the titles so that they category and pipes are removed and the entries are coloured in. Edit the calendar page (Site Actions -> Edit Page) and insert a content editor web part UNDER the calendar list view. Paste the following javasript into the source view. Make the web part hidden.

 <script>  
 var SEPARATOR = "|||";  
 var nodes, category;  
 nodes = document.getElementsByTagName("a");  
 function getObjInnerText (obj)  
 {  
   return (obj.innerText) ? obj.innerText : (obj.textContent) ? obj.textContent : "";  
 }   
 for(var i = 0; i < nodes.length; i++)  
 {  
   if(getObjInnerText(nodes[i]).indexOf(SEPARATOR) != -1)  
   {  
     UpdateCalendarEntryText(nodes[i]);  
     var foundNode = nodes[i];  
     var trap = 0;  
     while(foundNode.nodeName.toLowerCase() != "td")  
     {  
       foundNode = foundNode.parentNode;  
       trap++;  
       if(trap > 10)  
       {  
         break; // don't want to end up in a loop  
       }  
     }  
     var colourinfo = GetCalendarColourInfo(category);  
     if(colourinfo.bg != "")  
     {  
       foundNode.style.background = colourinfo.bg;  
     }  
     // try and update the text colour if we can TD/A/NOBR/B/#text  
     if(colourinfo.fg != "")  
     {  
       try  
       {  
         // there should only be one anchor tag  
         childNodes = foundNode.all;  
         for(var j = 0; j < childNodes.length; j++)  
         {  
           if(childNodes[j].nodeName.toLowerCase() == "a")  
           {  
             // found anchor tag  
             childNodes[j].style.color = colourinfo.fg;  
             // set the NOBR tag as well to set the time if it is shown, but set it on the B tag for month view  
             if(childNodes[j].children[0].nodeName.toLowerCase() == "nobr")  
             {  // month view has an extra b tag surrounding the text  
               childNodes[j].children[0].style.color = colourinfo.fg;  
               if(childNodes[j].children[0].children[0].nodeName.toLowerCase() == "b")  
               {  
                 childNodes[j].children[0].children[0].style.color = colourinfo.fg;  
               }  
             }  
             break;  
           }  
         }  
       }  
       catch(e) {}  
     }  
   }  
 }  
 function ColourInfo(bg, fg)  
 {  
   this.bg = bg;  
   this.fg = fg;  
 }  
 function UpdateCalendarEntryText(anchorNode)  
 {  
   var children = anchorNode.childNodes;  
   for(var i = 0; i < children.length; i++)  
   {  
     if(children[i].nodeType == 3 && children[i].nodeValue.indexOf(SEPARATOR) != -1)  
     {  
       var parts = children[i].nodeValue.split(SEPARATOR);  
       category = parts[0];  
       children[i].nodeValue = parts[1];      
     }  
     else  
       UpdateCalendarEntryText(children[i]);  
   }  
 }  
 function GetCalendarColourInfo(desc)  
 {  
   var colour = new ColourInfo("", "");  
   var trimmed = desc.replace(/^\s+|\s+$/g, '') ;  
   switch(trimmed.toLowerCase())  
   {  
     case "appointment":  
           colour.bg = "#ffd266";  
           colour.fg = "";  
           break;  
           case "birthday":  
           colour.bg = "#ae99dc";  
           colour.fg = "";  
           break;  
           case "business":  
           colour.bg = "#8aabe0";  
           colour.fg = "";  
           break;  
           case "important":  
           colour.bg = "#e77379";  
           colour.fg = "";  
           break;  
           case "vacation":  
           colour.bg = "#fffa91";  
           colour.fg = "";  
           break;  
     default:  
     {  
       colour.bg = "";  
       colour.fg = "";  
     }  
   }  
   return colour;  
 }  
 </script>  


You should now have a coloured calendar! Month, week and day views should appear coloured. Remember that if you place a calendar web part on a site that you will need a hidden content editor web part containing the javascript as well.



If you want to change the categories and colours, then simply add or change entries in the choice column and change the function in the Javascript accordingly.

In an ideal world this would be some sort of deployable feature, perhaps custom list definition. I will have a look at doing this at some point if I get time....

No comments:

Post a Comment