| | Stumble It! | Add to Mixx! | | diigo it | | Slashdot |

Thursday, October 9, 2008

SharePoint Calendar Reports

I've inadvertently produced two posts covering this topic. To see the most updated post, go here.

Thanks.

I've been working on a new project for the last couple days that is going to be a replacement system for tracking events and displaying them on a calendar in SharePoint. The calendar view needs to be able to show the following information in one glance:
  • Start Time
  • Emergency Flag
  • Event ID
  • Event Status
  • Event Impact
I managed to fit all this information into a single line of text that is displayed on the calendar like this:
Here's what the user is supposed to be able to understand by looking at this screen:
  1. The time is obviously when the event begins.
  2. The !!! indicates that the event is an emergency.
  3. The #XXX indicates the event ID and the color indicates the status of the event (Pending, Completed, Rescheduled).
  4. The color of the indicates the impact of the event (Routine, Moderate, Serious).
  5. Hovering the mouse over an event will display a short summary of the event so that the reader can skip from event to event without having to follow a click-trail.
Here's how I solved this problem...

From the grand scale, it's a two part solution:
  1. Building the HTML code to format and display the information.
  2. Using the previously mentioned Content Editor Web Part trick to write the HTML code from step 1 to executable code.
First, a code barf:
=CONCATENATE(" <nobr title='",Status,":",[Short Description],"' style='font-weight:lighter;color:",IF(ISERROR(SEARCH("Completed",Status,1)),(IF(ISERROR(SEARCH("Pending",Status,1)),(IF(ISERROR(SEARCH("Rescheduled",Status,1)),,"blue")),"red")),"green"),"'>",(IF(ISERROR(SEARCH("Emergency",Classification,1)),,"<span style='color:red;font-size:15px;font-weight:900' title='EMERGENCY!!!'> !!!</span>"))," #",[ID],"<span style='color:",IF(ISERROR(SEARCH("1 - Routine",Impact,1)),(IF(ISERROR(SEARCH("2 - Moderate",Impact,1)),(IF(ISERROR(SEARCH("3 - Severe",Impact,1)),,"red")),"blue")),"green"),";font-size:15px;font-weight:900' title='Impact: ",Impact,"'> •</span></nobr><tag>")
Copy/pasting this code into a calculated column will create the HTML for each event. Now I'll break it down a bit so that it's more easily understood:

=CONCATENATE(
This tells SharePoint to put the everything that follows into a string.

" <nobr title='",Status,":",[Short Description],"' style='font-weight:lighter;color:",IF(ISERROR(SEARCH("Completed",Status,1)),(IF(ISERROR(SEARCH("Pending",Status,1)),(IF(ISERROR(SEARCH("Rescheduled",Status,1)),,"blue")),"red")),"green"),"'>"
This block creates the color of the ID number based on the [Status] of the event.

,(IF(ISERROR(SEARCH("Emergency",Classification,1)),,"<span style='color:red;font-size:15px;font-weight:900' title='EMERGENCY!!!'> !!!</span>"))
This block adds the !!! flag if the event is classified as an emergency.

," #",[ID],"<span style='color:",IF(ISERROR(SEARCH("1 - Routine",Impact,1)),(IF(ISERROR(SEARCH("2 - Moderate",Impact,1)),(IF(ISERROR(SEARCH("3 - Severe",Impact,1)),,"red")),"blue")),"green"),";font-size:15px;font-weight:900' title='Impact: ",Impact,"'> •</span></nobr><tag>")
This block creates the • and adds the identifier for step 2 to take over.
Once I got the calculated column to create the HTML code that builds my display working, all I had to do was add the javascript code to rewrite the displayed code as executed code. This is accomplished using a Content Editor Web Part (CEWP) that is added to the calendar.aspx page below the calendar.

Again, a code barf:
<script type="text/javascript">
var theTags = document.getElementsByTagName("A");
var i=0;
while (i < theTags.length)
{
try
{
TagContent = theTags[i].innerText || theTags[i].textContent;
if (TagContent.indexOf("<tag>") >= 0)
{
theTags[i].innerHTML = TagContent;
}
}
catch(err){}
i=i+1;
}
</script>
This code is MUCH cleaner and easier to explain. Thankfully Javascript doesn't make you put everything on one line like SharePoint does.
<script type="text/javascript">
var theTags = document.getElementsByTagName("A");
var i=0;
This block creates an array (theTags) that is loaded with every <A> tag on the page.

while (i < theTags.length)
{
try
{
This block tells your browser to loop through every entry in theTags array.

TagContent = theTags[i].innerText || theTags[i].textContent;
if (TagContent.indexOf("<tag>") >= 0)
{
theTags[i].innerHTML = TagContent;
}
This block takes every entry in theTags and searches it for the <tag> that the calculated column included to identify it for processing by this step. If an entry has the identifier included in it, that entry is rewritten as executed HTML code by the theTags[i].innerHTML = TagContent; line.

}
catch(err){}
i=i+1;
}
</script>
This block ends the script and handles any errors quietly
I realize that this may not be the most elegant presentation of a solution and I'm happy to help anyone step through it if you have a question or problem implementing this code. Just post a question here and I'll reply as soon as I can.

3 comments:

tbaer said...

Ben,

I have been trying to figure out how to display a color coded calendar as you have done, so much thanks to your for your posting. I am having an issue getting this to work though. I have created step 1 as you recommended and have a column called HTML which I have included in my events list. The resultant entry in the field from adding a new Event is as follows:

<nobr title='Residential' style='font-weight:lighter;color:red'></nobr><tag>"

This is as expected. The problem is that step two will not render the field or display the event. I have modified the view to use the HTML field as the 'Month View Title' and it still does not display. Any thoughts?

Ben said...

tbaer,

I notice that in the HTML output, there's nothing between the NOBR tags. If this were executed as page code there would be nothing to display. In the calculated column, you need to include something after "...color:red'>" and before "</nobr>". This way, when the code is executed (instead of just displayed) whatever you have put between the tags will show on the calendar.

If that doesn't work, try sending me a screen shot of the calendar when you view it and I'll see what I can do.

-Ben

tbaer said...

Doh! That did it. Great Work!!!