An expanded version of this article, along with many other customization examples and how-tos can be found in my book, SharePoint 2007 and 2010 Customization for the Site Owner.
Updated 9/6/11
Service Pack 1 broke my color coded calendar code! For details see here. The code below has been updated to work with both the pre-SP 1 and SP 1 installations.
Updated 2/20/11
As I’m working on my customization book I am revisiting every one of my past “quick tips”. As I do so I am often finding a better way to do something. I ran into some issues working around the asynchronous loading of calendar events with the article below. After digging more into the code behind the calendar pages in 2010 I have found a much better way to trigger the color coding code. The sections that have been replaced below are now crossed out (aaaaaa) and the new content added.
This update also solves most of the issues found in the comments at the end of this article, especially the “more items” problem.
Color Coded Events in SharePoint 2010 Calendars
Back in 2008 I wrote a little blog article on adding color to SharePoint 2007 calendar events. Several people have been pestering me to update it for SharePoint 2010, so here goes...
Several things have changed between SharePoint 2007 and 2010 to prevent the old example from working. For fellow “SharePoint client side hackers” I thought I would document the trail I followed to get color coding to work in 2010. For those who do not care about the details, just scroll on down to “Color Coded Events in SharePoint 2010 Calendars Step by Step”.
They broke the Content Editor Web Part!
In 2010 it’s now just called “Content Editor” and is in the “Media and Content” section of Add a Webpart:
When you add this web part you get a “wiki style” editor. Just click in the new web part and start typing. The Ribbon will then be updated to show all of the Rich Text editor options.
How do you add HTML?
You can just click the HTML button in the Ribbon ( ). But read on for some fun issues with this option…
But when you add CSS or JavaScript you may get this nice little message!
As a trivial example I entered:
<style>
.s4-titletext h1 a
{
color:red
}
</style>
and it reformatted it as:
<style>
.s4-titletext h1 a
{
color:red
}</style>
and each time you go back into the HTML editor and click OK and adds another blank line after <STYLE>
<style>
.s4-titletext h1 a
{
color:red
}</style>
It has even changed capitalization. In one of my edits it changed color:red to COLOR:red.
Who knows why….
So add your code directly to the page
Use SharePoint Designer and add the code to the bottom of the view page. The best place is most likely between the “</WebPartPages:WebPartZone>” tag and the “</asp:Content>” tag. If you are using SharePoint Designer 2010 you will need to click “Advanced Mode” in the ribbon to edit that area.
Or just link to your code!
Both 2007 and 2010 offer the option to link from the CEWP to a text file with our content. So for 2010 I usually upload a text file containing the code to a library. Then in the CEWP just click the “Edit Web Part” option in the dropdown and add the link to the code file.
They broke the Calendar!
Not really, but is sure has changed. In 2007 the calendar was created entirely server side. The HTML sent to the browser was the final, ready to display HTML. All we needed to do was to write a little JavaScript and/or CSS to “customize” it.
Why it’s now a bit harder to code…
In 2010 the data for the calendar is now asynchronously loaded using a JavaScript function call after the page is loaded. That means that the data we want to change is not yet in the browser when our JavaScript is loaded from a Content Editor Web Part. If you have played with SharePoint client side JavaScript then you have seen the following command used to run a function after the page has loaded.
_spBodyOnLoadFunctionNames.push("_spAjaxOnLoadWaitWPQ2")
Note: _spBodyOnLoadFunctionNames is just a JavaScript array and push is a JavaScript method to add a new item to the end of the array. When a SharePoint page is loaded each function listed in this array is called in order.
I have used this often in 2007 to make sure the page is fully loaded before my JavaScript runs. The problem is where Microsoft loaded this for calendars in 2010… at the very end of the page. That means that when I use a Content Editor Web Part to add my JavaScript it will be in the “queue” before the JavaScript used to add the calendar events. So my challenge now is to get my code to run after the code that loads the calendar.
The work around?
The work around? We have to get our function added to _spBodyOnLoadFunctionNames after SharePoint's calendar update function. One way is to add our JavaScript in the master page and write the code so it only impacts calendars. But that’s a bad workaround. We would then have JavaScript that’s only needed for calendars added to every page.
So here’s another workaround… (Have a better idea? Let me know!) Add a bit of JavaScript at the bottom of the master page that checks for an array of my functions that need to be run. If there’s no array, then do nothing…
<script type="text/javascript">
if (window.mikesCode)
{
for (var i=0;i<mikesCode.length;i++)
{
_spBodyOnLoadFunctionNames.push(mikesCode[i]);
}
}
</script>
Then in the Content Editor Web Parts (or anywhere else) add a custom function and add it to my little array.
function DoSomethingCool()
{
// code here
}
if (!window.mikesCode)
{
mikesCode=new Array(); // create mikesCode if it does not exist
}
mikesCode[mikesCode.length] = "DoSomethingCool"; //add the function to run
Now we have all of the pieces… (but I’m not finished with this article… I want to find a way to do this without the master page edit)
The new “work around!”
To get our code to run at the right time we need to hook into the SharePoint code that loads the calendar items. Once such place is a function named "SP.UI.ApplicationPages.CalendarNotify.$4a".We also need to delay the load of our code, and we can do that with a SharePoint feature named "_spBodyOnLoadFunctionNames.push".
As a result of this change I can now eliminate the need for the master page edit. (That trick is still useful for other kinds of customizations.)
Color Coded Events in SharePoint 2010 Calendars Step by Step
Add a little piece of code to the master page
Open SharePoint Designer 2010 and open your site
In the Navigation pane and in the Site Object section click Master Pages
Click your master page (most likely “v4.master”) and if asked, check it out
In Customization section click “Edit file”
Scroll to the bottom of the file and just before the </body> tag add the script below
Save the file and then check it in
<script type="text/javascript">
if (window.mikesCode)
{
for (var i=0;i<mikesCode.length;i++)
{
_spBodyOnLoadFunctionNames.push(mikesCode[i]);
}
}
</script>
Setup the Calendar
The steps here are identical to the SP 2007 article.
- Create or open a calendar
- Add a new column named "Color" – most likely type will be "Choice" with choices like "Red, Green, Blue, Black", but this could be a lookup or a single line of text.
(See here for an HTML color chart: http://www.w3schools.com/html/html_colornames.asp)
- Add a new column named "CalendarText"
- Column Type is Calculated
- Equation is:
="<font color='" & Color & "'>" & Title & "</font>"
- Data type returned = single line of text
- Modify the existing view, or create a new view such as "Color Calendar"
- Change the field used for the Month View Title AND Day View Title AND Week View Title to "CalendarText"
- Save and exit (The HTML for "<FONT" will now be displayed. Some JavaScript will be needed to fix the HTML tags)
Create the JavaScript file
Two Solutions!
1) Add a Content Editor Web Part as we have done in many of the other customizations. The problem with this approach is that SharePoint 2010 will no longer treat this page as a view. When this page is displayed you will see two changes:
· The View dropdown list in the site title area is missing
· The Ribbon will not be displayed when the page is first loaded, but will be displayed when any event item is clicked.
2) Add the custom JavaScript using SharePoint Designer. The page will then display as an ordinary view no odd behavior.
I recommend #2.
Option #1: Using the Content Editor Web Part
I usually add a library named Scripts, ScriptFiles or similar for these kinds of files. The steps below will just use the Shared Documents library.
- Open Windows Notepad and add the script below
- Save the file with a name like “CalendarColorScript.txt”
- Upload the text file to your library (Shared Documents in this example)
<script type="text/javascript" language="javascript">
function CalColor()
{
var x = document.getElementsByTagName("div")
var i=0;
for (i=0;i<x.length;i++)
{
if (x[i].className=="ms-acal-item")
{
x[i].innerHTML= x[i].innerHTML.replace(/</g,'<').replace(/>/g,'>')
}
}
}
// hook into the SharePoint JS library to call our code
// whenever the calendar is updated
function CalHookIntoSPUI()
{
var originalCalendarNotify = SP.UI.ApplicationPages.CalendarNotify.$4a;
//var originalresetSelection = SP.UI.ApplicationPages.CalendarViewBase.prototype.resetSelection;
SP.UI.ApplicationPages.CalendarNotify.$4a = function()
{
originalCalendarNotify();
CalColor();
}
}
// add to the array of functions to run from the master page code
if (!window.mikesCode)
{
mikesCode=new Array();
}
mikesCode[mikesCode.length] = "CalColor";
mikesCode[mikesCode.length] = "CalHookIntoSPUI";
</script>
(updated 9/6/2011)
<script>
// Color coded calendars for SharePoint 2010
// TechTrainingNotes.blogspot.com
// load our function to the delayed load list
_spBodyOnLoadFunctionNames.push('colorCalendarEventLinkIntercept');
// hook into the existing SharePoint calendar load function
function colorCalendarEventLinkIntercept()
{
if (SP.UI.ApplicationPages.CalendarNotify.$4a)
{
var OldCalendarNotify =
SP.UI.ApplicationPages.CalendarNotify.$4a;
SP.UI.ApplicationPages.CalendarNotify.$4a = function ()
{
OldCalendarNotify();
colorCalendarEventLinks();
}
}
if (SP.UI.ApplicationPages.CalendarNotify.$4b)
{
var OldCalendarNotify =
SP.UI.ApplicationPages.CalendarNotify.$4b;
SP.UI.ApplicationPages.CalendarNotify.$4b = function ()
{
OldCalendarNotify();
colorCalendarEventLinks();
}
}
// future service pack change may go here!
// if (SP.UI.ApplicationPages.CalendarNotify.???)
}
// hide the hyperlinks
function colorCalendarEventLinks()
{
// find all DIVs
var divs = document.getElementsByTagName("DIV");
for (var i=0;i<divs.length;i++)
{
// find calendar item DIVs
if (divs[i].className.toLowerCase()=="ms-acal-item")
{
divs[i].innerHTML = divs[i].innerHTML.replace(/</g,'<').replace(/>/g,'>');
}
// find "x more items" links and re-remove links on Expand/Contract
if (divs[i].className.toLowerCase()=="ms-acal-ctrlitem")
{
var links = divs[i].getElementsByTagName("A");
if (links.length==1)
{
links[0].href="javascript:colorCalendarEventLinks();void(0);"
}
}
}
}
</script>
Add a Content Editor Web Part to hold the JavaScript
- Go to the document library where you uploaded the script file, right-click the file name and select Properties
- Copy the URL to the file and click OK
- Display your calendar and select the view you modified earlier
- Click Site Actions and then Edit Page
- Click “Add a Web Part” and select the Content Editor web part
- In the new web part’s dropdown menu click “Edit Web Part”
- Paste in the URL to the script file you copied in step 2
- Click OK
- In the Ribbon click “Stop Editing” (in the Page tab)
Option #2 Using SharePoint Designer
This is the preferred method as it does not break view related functionality as does adding a web part.
- Go to the calendar in the browser and create a new view (maybe "Calendar - No Links")
- Open your site in SharePoint Designer 2010
- Click Lists and Libraries in the Site Objects pane
- Click your calendar list and click the new view
- In the ribbon click the "Advanced Mode" link (so you can edit the entire page)
- Search for "</WebPartPages:WebPartZone>" and insert a new line just after this tag
</WebPartPages:WebPartZone>
your customization goes here (don't type this J )
</asp:Content>
- Add the JavaScript from below
- Save your changes in SharePoint Designer
- Go to the calendar, add a new event and select a color, and see if the colors are displayed.
Everything (or at least option #1) comes with a price :-(
The above works! But… you lose one feature. When you add a web part to a view you lose the ability to select a view from the crumb trail. (This is not a problem if you add the code using SharePoint Designer)
Without a web part on the page:
With a web part on the page: (this is our “Color Calendar” view)
Notice that the crumb trail now only has the list name. The view name is missing. When the view name is displayed then you also have the dropdown to select other views
You can still switch views, but you must first click in the calendar to display the ribbon.
Bug? Probably. (So use option #2 – add the code with SharePoint Designer)
Some thoughts on color options…
Just change the FONT tag to a SPAN tag and use a style. Example:
="<span style='background-color:"&Color&"'>"&Title&"</span>"
This works, but the background is for just the width of the text, not the entire table cell.
You will probably want to use colors like lightblue, lightgreen, tomoto (light red would just be Pink!), etc. or make the text white or a light color:
="<span style='color:white;background-color:"&Color&"'>"&Title&"</span>"
Closing Notes
- Document everything, and add to your disaster recovery plan (otherwise you’ll never remember how you did this,and consider the poor person who inherits this site from you)
- In researching the SP.UI.ApplicationPages.CalendarNotify update I found a blog article by Mark Wilson that also intercepted the SP.UI.ApplicationPages.CalendarViewBase.prototype.resetSelection function. My code seems to work fine without it. But in any case go take a look at Mark’s article to see another approach to color coded calendars.
- This has been tested only with IE 8 and FF 3.5.9 so far.
- Batteries not included, your mileage may vary, please test, test, test…
.