I was interviewing for a new position and one of the questions that was asked of me: How would you overcome the limit of 10 overlays on the SharePoint 2010 calendar? I answered, after a moments reflection, that I would probably use some custom JavaScript and create a content type inheriting from the built-in Content Type Event. A complete shot in the dark, as I had never had occasion to investigate this problem in all of my SharePoint development! I did some Google\Bing investigation and looked at a few blogs and decided that my initial stab in the dark would be a way of accomplishing this feat! So here is my take on this problem: A complete solution that has all the bells and whistles needed that activates a few features and we have a working deployable calendar. Some of the issues I saw with other solutions was that in using SPSite Data Query (Rollup) you either need to look for specific lists or use the template ID which would mean that you would roll up all calendars in the site collection or using specific lists, If a new calendar was added in the site collection the code would need to be changed. Thus if we want to get calendars specifically created for rollup then we need a different content type.
Summary of what we are going to do:
1. Create an empty SharePoint 2010 project
2. Add some housekeeping folders.
3. Add some Modules to get our content into SharePoint
4. Create a new Content Type called RollUpCalendarContentType. With associated artifacts.
5. Create the Calendar Web Part
6. Create some Artifacts need to make the calendar work
5. Complete the solution add a master with JQuery and a Page layout.
Create Empty SharePoint 2010 Project
Add new folder called Modules and add two Modules to this folder called CSS and Scripts.
Add JQuery to the scripts module and rename Sample.txt to calScripts.js
I have an Extension and Utilities Classes that I add to all my projects that will create Lists and Content Types. They will be part of this Project at CodePlex
Create a Folder called Code and add these classes to the folder changing names spaces to reflect this project. I know some would say create a DLL and reference that in your project but I have had occasion to use a 3rd party solution where the DLL was not available so I choose to keep my dependencies self contained as much as possible. I won’t describe these artifacts as it is not germane to this blog entry. I describe them in detail in a pervious post Creating Lists and Content Types : List Instance
We need to create a Content Type that inherits from Event so lets create an Event Receiver and Create one. When we added our Modules Visual Studio in its Goodness automatically added a Feature called feature1 let’s rename it to AddCalendarArtifacts this will be a feature that is site scoped so we can add the Scripts, CSS, Site Columns and Content Type within this feature. The Scripts and CSS Modules are already added to this feature so we need to add an Event Receiver here to add our content type.
The difference between this content type and Event is that I will be adding a look up field which will lookup a a category from a List called CalendarCategories from the Title column and a new column called MilCategory. Therefore I need to create a list instance called “CalendarCategories”. Since this list will only be instantiated at the Site Collection level we can add this list instance in this event receiver. Here is the Event Receiver:
using System; using System.Runtime.InteropServices; using System.Security.Permissions; using Microsoft.SharePoint; using Demo.Calendar.Code; using System.Collections; namespace Demo.Calendar.Features.AddCalendarArtifacts { [Guid("4c1beeb2-9bb5-488f-8220-53e2627b6ebe")] public class AddCalendarArtifactsEventReceiver : SPFeatureReceiver { const string columnGroup = "Demo"; const string ctName = "RollUpCalendarContentType"; // Uncomment the method below to handle the event raised after a feature has been activated. public override void FeatureActivated(SPFeatureReceiverProperties properties) { using (SPWeb spWeb = properties.GetWeb() as SPWeb) { if ((spWeb.Lists.TryGetList("CalendarCategories") == null)) { //create the list if it doesn't exist CreateCalendarCategoryList(spWeb); } //add the fields addFields(spWeb); //add content type SPContentType testCT = spWeb.ContentTypes[ctName]; // we will not create the content type if it exists if (testCT == null) { //the content type does not exist add it addContentType(spWeb, ctName); } } } public void addFields(SPWeb spWeb) { Utilities.addLookupField(spWeb, "CalendarCategories", "Title", "MilCategory", columnGroup); } private static void addContentType(SPWeb spWeb, string name) { SPContentType myContentType = new SPContentType(spWeb.ContentTypes["Event"], spWeb.ContentTypes, name) { Group = columnGroup }; spWeb.ContentTypes.Add(myContentType); addContentTypeLinkages(spWeb, myContentType); myContentType.Fields.Delete("Category"); myContentType.Update(); } public static void addContentTypeLinkages(SPWeb spWeb, SPContentType ct) { Utilities.addContentTypeLink(spWeb, "MilCategory", ct); } private void CreateCalendarCategoryList(SPWeb web) { Guid newListGuid = web.Lists.Add("CalendarCategories", "Calendar Categories.", SPListTemplateType.GenericList); SPList newList = web.Lists[newListGuid]; ArrayList choices = new ArrayList() { "Training", "Deploymment", "Deployed" }; foreach (string iTem in choices) { SPListItem itemToAdd = newList.Items.Add(); itemToAdd["Title"] =iTem; itemToAdd.Update(); } newList.Update(); } } }
Now that we have all of this in a solution, Why not just build a web template? I think it is and a topic for another blog entry!
Here is a screen shot with the project deployed and activated:
Click and add a new site, Name it Subsite1:
Go to Settings and activate the site feature:
Go to View all Site Content and click on RollupCalendar add a test entry:
Go back to the Calendar page:
For Demo purposes I will create a sub site I know is not in the JavaScript, I will create a sub site named: NewSite and added the roll up calendar with a dummy test entry, if we go back to the Calendar page we will see the entry but without any color:
I have dummy site names in the calendar.html (JavaScript) so if we add a site not on the original rollout then open the Calendar.html in SharePoint Designer:
Notice there isn’t any site named NewSite, Change one of the unused entries to NewSite (These are caps sensitive).
Last thing is how we change colors on the calendar. Just open up DemoCalendar.css for the Styles library:
I have entries in here for 5 sites. Notice it is a style for the class and its link to fine tune the style. Use your design skills!
I added the feature to change the master page of the site to ensure JQuery.
For development, Create a new site collection, activate the features, There are some dependencies, which might come in to play if you deploy this from visual studio. If that happens, just redeploy! it will fix it!. You will know if everything deployed correctly if the Calendar page deploys approved: