As we develop our SharePoint 2010 environment, we are looking for ways to keep the site alive and relevant. In a sense, to turn SharePoint from the Corporate Intranet stereotype of an online repository of business documents.

One feature that all of our regional office managers really liked was the ability to manage a single calendar in SharePoint for their respective region’s main events. With this request for a central calendar came the need for displaying a short list of upcoming events.

This article covers how I was able to accomplish this requirement without resorting to custom development or code. This was all done completely from the SharePoint web UI.

A Little History on the Business Case

In the beginning this seemed easy:

  • Let’s create a SharePoint 2010 Calendar
  • Let’s create a list view that only shows the next four events.
  • Let’s put that list view web part on the home page

Simple, right?

But there was a catch!

  • We wanted a very specific look and feel.
  • We wanted to have the Date show up as April 29, and not the default Start Time field of full date plus time stamp (4/29/2011 12:00 AM).

So the next step was to turn to a favorite hack of mine to get SharePoint to display what I want without resorting to custom code: Christophe’s HTML Calculated Columns JavaScript trick (see my article on Using Calculated columns to write HTML)

With this trick I proceeded to create a calculated column that converted the Start Time to the desired format of Month ##. I then created a custom view using the Standard View, with Expanded Recurring Events template.

As soon as I did this things looked great at first until I noticed two problems:

  1. For any recurring events, the calculated column only showed the first date of the event, not the current date on the repeating event.
  2. The custom view I created starts from the beginning of the first event date, and not the current date

Solution 1: getting dates to show up correctly

In order to get the correct date to show, I had to use the default Start Date column in my view. To address this column’s default display as full Date and Time, I injected some code into Christophe’s TextToHTML script to convert Date/Time values into the format I wanted.

  • First I added to the Javascript an isDate() function that I found here: http://www.codetoad.com/forum/17_10053.asp
  • I then added an else statement to Christophe’s TextToHTML Javascript as follows:

    function
    TextToHTML(NodeSet, HTMLregexp) {
    var
    CellContent = “”;
    var
    i=0;
    while
    (i < NodeSet.length){
    try
    {
    CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
    if
    (HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}

    // Adding else if statement to convert regular dates to custom format of MONTHNAME Date (e.g. April 29)
    else if
    (isDate(CellContent)) {
        NodeSet[i].innerHTML = formatDateAsMonthDay(NodeSet[i].innerHTML);
    } //end else if for custome date format

    }
    catch(err){}
    i=i+1;
    }
    }

  • I created my own function to convert the date format (If anyone can help me with a RegEX that would do better than my several lines of REPLACE, that would be nice. I was able to identify that any Date/Time column got surrounded by the <NOBR> tags and since nothing else on my home page uses this tag, it was safe to use this as the unique identifier for my date formatting:

    function
    formatDateAsMonthDay(dateStr) {
        var
    formattedDate;
        var
    m_names = new
    Array(“January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November”, “December”);

        var
    DateString = dateStr;

        //get rid of the <NOBR> tag
        DateString = DateString.replace(“<NOBR>”,””);
        DateString = DateString.replace(“</NOBR>”,””);

        //Date is formatted as 4/29/2011 8:00 AM. This split will just get me the date w/o the time stamp.
        DateString = DateString.split(” “)[0];
        

        var
    d = new
    Date(DateString);
        var
    curr_date = d.getDate();
        var
    curr_month = d.getMonth();

        formattedDate = “<div class=’eeEventWorkaround_Date’>” + m_names[curr_month] + ” ” + curr_date + “</div>”;
        return
    formattedDate;
    }

By putting these three scripts together, I was able to utilize Christophe’s code, which scans the entire page for HTML and add the functionality to find any Date strings and format them accordingly.

Some potential problems with this are that the code is indiscriminant of what kind of content. If the first part of a cell of data in any table on the page has content of Date/Time format, it will get formatted. This worked in my case since the only Date/Time formatted content was in the list view of the event calendar

Solution 2: getting the list to show current events and not from the start.

To accomplish this, I did the following steps:

  • Created an EventTitleHTML Calculated Columns for custom display:
    • EventTitleHTML
      =”<div class=””_Event””>”&Title&”</div>”
      (note: the surrounding DIV tags is what the TextToHTML Javascript finds and causes the page to render the HTML instead of displaying the HTML tags as text)’
  • Created a Yes/No column called Show on Home Page.
  • Created a StartDate Calculated column that pulls the Start Time in Date format only (no time)
  • Created an EndDate Calculated column that pulls the End Time in Date format only (no time)
  • Created a custom view to display upcoming events. Read on for an explanation on this one.

I found a good article on Microsoft’s forum and was able to adapt it to my needs: filter Recurring Event by Start/End Time… By use of some creative filtering, I was able to get the view to show the upcoming 4 events – a good snapshot of what’s to come.

By following the steps in this article, I was able to get my list view to display what I needed. Rather than type out the steps, I’ll give you a screenshot of how my view was built. The only difference between my view and what was suggested in this post is the filter statements, since I wanted to give our office managers the ability to indicate whether a calendar event will display on the home page or not:

The only thing to note on the above image is that when I initially created this view, I used the Standard View, with Expanded Recurring Events, and then unchecked ALL but the Start Time and the Calculated Column. You see the Recurrence column still checked since this type of view cannot have the recurrence removed. It will automatically get re-checked once you save, but will subsequently not show up in the view when used in a web part.

The Result

Apply some CSS and here is the final result!

I hope this helps you or you can glean some tricks off this post!

4 Responses to “SharePoint 2010 Calendar List views and recurring events – An adaptation of using Calculated Columns to write HTML”

  1. Michael Vasquez

    Tried your script and it did not work. Here is the script of yours I put together. What I want to do is have the recurring Start Time show the correct date that was posted on the Calendar.

    /*
    Text to HTML - version 2.1.1
    Questions and comments: Christophe@PathToSharePoint.com
    */

    function TextToHTML(NodeSet, HTMLregexp) {
    var CellContent = "";
    var i=0;
    while (i < NodeSet.length){
    try {
    CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
    if(HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}
    else if
    (isDate(CellContent)) {
    NodeSet[i].innerHTML = formatDateAsMonthDay(NodeSet[i].innerHTML);
    }
    }
    catch(err){}
    i=i+1;
    }
    }

    // Calendar views
    var regexpA = new RegExp("\\s*\\s*");
    TextToHTML(document.getElementsByTagName("a"),regexpA);

    // List views
    var regexpTD = new RegExp("^\\s*\\s*$");
    TextToHTML(document.getElementsByTagName("TD"),regexpTD);

    // Grouped list views
    ExpGroupRenderData = (function (old) {
    return function (htmlToRender, groupName, isLoaded) {
    var result = old(htmlToRender, groupName, isLoaded);
    var regexpTD = new RegExp("^\\s*\\s*$");
    TextToHTML(document.getElementsByTagName("TD"),regexpTD);
    };
    })(ExpGroupRenderData);

    // Preview pane views
    if (typeof(showpreview1)=="function") {
    showpreview1 = (function (old) {
    return function (o) {
    var result = old(o);
    var regexpTD = new RegExp("^\\s*\\s*$");
    TextToHTML(document.getElementsByTagName("TD"),regexpTD);
    };
    })(showpreview1);
    }

    function
    formatDateAsMonthDay(dateStr) {
    var
    formattedDate;
    var
    m_names = new
    Array(“January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November”, “December”);
    var
    DateString = dateStr;

    //get rid of the tag
    DateString = DateString.replace(“”,”");
    DateString = DateString.replace(“”,”");

    //Date is formatted as 4/29/2011 8:00 AM. This split will just get me the date w/o the time stamp.
    DateString = DateString.split(” “)[0];
    var
    d = new
    Date(DateString);
    var
    curr_date = d.getDate();
    var
    curr_month = d.getMonth();

    formattedDate = “” + m_names[curr_month] + ” ” + curr_date + “”;
    return formattedDate;
    }

  2. social media

    I’ve been surfing online greater than 3 hours as of late, but I by no means found any attention-grabbing article like yours. It’s lovely price enough for me. In my view, if all web owners and bloggers made just right content as you probably did, the web shall be a lot more useful than ever before.

  3. Lee Jay

    This is exactly the help I what I was looking for. I was already rendering colors in both a list and calendar on my page using Christophe’s java script, but when I added the three new scripts the revised java script posted to the CEWP didn’t work eg I lost my color rendering. Any ideas? Thanks!

    Here’s the script I used:

    /*
    Text to HTML – version 2.1.1
    Questions and comments: Christophe@PathToSharePoint.com
    */

    function TextToHTML(NodeSet, HTMLregexp) {
    var CellContent = “”;
    var i=0;
    while (i < NodeSet.length){
    try {
    CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
    if (HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}

    // Adding else if statement to convert regular dates to custom format of MONTHNAME Date (e.g. April 29)
    else if
    (isDate(CellContent)) {
    NodeSet[i].innerHTML = formatDateAsMonthDay(NodeSet[i].innerHTML);
    } //end else if for custome date format

    }
    catch(err){}
    i=i+1;
    }
    }

    // Calendar views
    var regexpA = new RegExp("\\s*\\s*”);
    TextToHTML(document.getElementsByTagName(“a”),regexpA);

    // List views
    var regexpTD = new RegExp(“^\\s*\\s*$”);
    TextToHTML(document.getElementsByTagName(“TD”),regexpTD);

    // Grouped list views
    ExpGroupRenderData = (function (old) {
    return function (htmlToRender, groupName, isLoaded) {
    var result = old(htmlToRender, groupName, isLoaded);
    var regexpTD = new RegExp(“^\\s*\\s*$”);
    TextToHTML(document.getElementsByTagName(“TD”),regexpTD);
    };
    })(ExpGroupRenderData);

    // Preview pane views
    if (typeof(showpreview1)==”function”) {
    showpreview1 = (function (old) {
    return function (o) {
    var result = old(o);
    var regexpTD = new RegExp(“^\\s*\\s*$”);
    TextToHTML(document.getElementsByTagName(“TD”),regexpTD);
    };
    })(showpreview1);
    }

    function isDate(dateStr) {

    var datePat = /^(\d{1,2})(\/|-)(\d{1,2})(\/|-)(\d{4})$/;
    var matchArray = dateStr.match(datePat); // is the format ok?

    if (matchArray == null) {
    alert(“Please enter date as either mm/dd/yyyy or mm-dd-yyyy.”);
    return false;
    }

    month = matchArray[1]; // p@rse date into variables
    day = matchArray[3];
    year = matchArray[5];

    if (month 12) { // check month range
    alert(“Month must be between 1 and 12.”);
    return false;
    }

    if (day 31) {
    alert(“Day must be between 1 and 31.”);
    return false;
    }

    if ((month==4 || month==6 || month==9 || month==11) && day==31) {
    alert(“Month “+month+” doesn`t have 31 days!”)
    return false;
    }

    if (month == 2) { // check for february 29th
    var isleap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
    if (day > 29 || (day==29 && !isleap)) {
    alert(“February ” + year + ” doesn`t have ” + day + ” days!”);
    return false;
    }
    }
    return true; // date is valid
    }

    function
    formatDateAsMonthDay(dateStr) {
    var
    formattedDate;
    var
    m_names = new
    Array(“January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November”, “December”);

    var
    DateString = dateStr;

    //get rid of the tag
    DateString = DateString.replace(“”,””);
    DateString = DateString.replace(“”,””);

    //Date is formatted as 4/29/2011 8:00 AM. This split will just get me the date w/o the time stamp.
    DateString = DateString.split(” “)[0];

    var
    d = new
    Date(DateString);
    var
    curr_date = d.getDate();
    var
    curr_month = d.getMonth();

    formattedDate = “” + m_names[curr_month] + ” ” + curr_date + “”;
    return
    formattedDate;
    }

    http://hqsms-spweb-001:113/2/5/Shared Documents/TextToHTML-v2.1.1.htm
    2500.00000000000

  4. Panda

    Hi Lee Jay, I probably won’t be able to troubleshoot your code, since I’m primarily copy/pasting Christophe’s code and trusting his coding genius to work.

    In my experience, SharePoint is extremely finicky with how the “current events” view works, especially when there are recurring events. I haven’t found any definitive way of creating a custom view to show upcoming events, including recurrence, short of the method I described above. I also found that when I created a new view with recurrence, the view would break if I made too many edits to its filters, column selections, etc.

    In the end, I spent a lot of time deleting and re-creating the view to get it to display correctly (lots of trial-and-error!).

    Might I suggest you start with Christophe’s code w/o any edits, and layer on your added code one sub-function at a time, and then test to see the results? This might help you narrow down where the error is. Be careful not to write anything or use variable names that override the original code unless you intend to do so.