"Connect to Outlook" feature is missing in the Calendar of Custom Calendar list Definition

Creating a custom list definition is not always a cake walk especially when it comes to Calendar. When you are creating a custom calendar definition based on the OOB “EventsList” you will end up in changing the “TemplateType” from “106” to your custom template type to have the unique identity of your template. Everything will be looking smooth when you install the definition and creates the calendar based on it until you observe the calendar carefully. Under the action menu of the toolbar “Connect to Outlook” feature will be missing…… Oops !!!!

It is because the SharePoint checks the TemplateType before rendering the MenuItem template in the Actions menu of the List. SharePoint wants to give the “Connect to Outlook” option only to certain list type like Events(Calendar) and Tasks. When it checks for the Template type of your custom calendar created from custom calendar definition whose TemplateType is not “106” then it restricts the “Connect to Outlook” MenuItem template to render.

All the List toolbar menu and the item form pages (NewForm.aspx,DispForm.aspx,EditForm.aspx… etc) toolbar are rendered based on the rendering template in the defaulttemplates.ascx control. It resides in the “ControlTemplates” folder of 12 hive.

“ActionsMenu” for the List toolbar are rendered by the rendering template with ID “ToolbarActionsMenu” in the defaulttemplates.ascx. SharePoint doesn’t have individual rendering template for each different list TemplateType Actions menu. It has the common rendering template “ToolbarActionsMenu” for all the List type,“ToolbarActionsMenuforSurvey” for the Survey List type and the “ToolbarActionsmenuforPictureLibrary” for the picture library document library type.

The “ToolbarActionsMenu” rendering template is based on FeatureMenuTemplate which consists individual “MenuItemtemplate”.

<SharePoint:RenderingTemplate ID="ToolbarActionsMenu" runat="server">

      <Template>

            <SharePoint:FeatureMenuTemplate runat="server"

                  FeatureScope="Site"

                  Location="Microsoft.SharePoint.StandardMenu"

                  GroupId="ActionsMenu"

                  UseShortId="true"

                  >

                  <SharePoint:MenuItemTemplate

                        ID="EditInGridButton"

                        ImageUrl="/_layouts/images/menudatasheet.gif"

                        PermissionsString="UseRemoteAPIs"

                        MenuGroupId="200"

                        Sequence="200"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="OpenInExplorer"

                        Text="<%$Resources:wss,ToolBarMenuItemOpenInExplorer%>"

                        Description="<%$Resources:wss,ToolBarMenuItemOpenInExplorerDescription%>"

                        PermissionsString="UseClientIntegration"

                        PermissionContext="CurrentList"

                        MenuGroupId="200"

                        Sequence="300"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="ChangeOrder"

                        Text="<%$Resources:wss,ToolBarMenuItemChangeOrder%>"

                        Description="<%$Resources:wss,ToolBarMenuItemChangeOrderDescription%>"

                        MenuGroupId="200"

                        Sequence="400"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="ShowInStdViewButton"

                        Text="<%$Resources:wss,ToolBarMenuItemShowInStdView%>"

                        Description="<%$Resources:wss,ToolBarMenuItemShowInStdViewDescription%>"

                        MenuGroupId="300"

                        Sequence="100"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="NewRowButton"

                        Text="<%$Resources:wss,ToolBarMenuItemNewRow%>"

                        Description="<%$Resources:wss,ToolBarMenuItemNewRowDescription%>"

                        PermissionsString="AddListItems"

                        PermissionContext="CurrentList"

                        MenuGroupId="300"

                        Sequence="200"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="TaskPaneButton"

                        Text="<%$Resources:wss,ToolBarMenuItemTaskPane%>"

                        Description="<%$Resources:wss,ToolBarMenuItemTaskPaneDescription%>"

                        MenuGroupId="300"

                        Sequence="300"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="TotalsButton"

                        Text="<%$Resources:wss,ToolBarMenuItemTotals%>"

                        Description="<%$Resources:wss,ToolBarMenuItemTotalsDescription%>"

                        MenuGroupId="300"

                        Sequence="400"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="RefreshDataButton"

                        Text="<%$Resources:wss,ToolBarMenuItemRefreshData%>"

                        Description="<%$Resources:wss,ToolBarMenuItemRefreshDataDescription%>"

                        MenuGroupId="300"

                        Sequence="500"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="OfflineButton"

                        Description="<%$Resources:wss,ToolBarWorkOfflineOutlookDescription%>"

                        PermissionsString="UseClientIntegration"

                        PermissionContext="CurrentList"

                        MenuGroupId="400"

                        Sequence="100"

                        ImageUrl="/_layouts/images/MenuPIM.gif"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="ExportToSpreadsheet"

                        Text="<%$Resources:wss,ToolBarMenuItemExportToSpreadsheet%>"

                        Description="<%$Resources:wss,ToolBarMenuItemExportToSpreadsheetDescription%>"

                        PermissionsString="UseClientIntegration"

                        PermissionContext="CurrentList"

                        MenuGroupId="400"

                        Sequence="200"

                        ImageUrl="/_layouts/images/MenuSpreadsheet.gif"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="ExportToDatabase"

            PermissionsString="UseClientIntegration"

                        PermissionContext="CurrentList"

                        MenuGroupId="400"

                        Sequence="300"

                        ImageUrl="/_layouts/images/MenuDatabase.gif"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="DiagramButton"

                        Description="<%$Resources:wss,ToolBarCreateDiagramDescription%>"

                        PermissionsString="UseClientIntegration"

                        PermissionContext="CurrentList"

                        MenuGroupId="400"

                        Sequence="500"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="ViewRSS"

                        Text="<%$Resources:wss,ToolBarMenuItemViewRSSFeed%>"

                        Description="<%$Resources:wss,ToolBarMenuItemViewRSSFeedDescription%>"

                        MenuGroupId="500"

                        Sequence="400"

                        ImageUrl="/_layouts/images/MenuRSS.gif"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="SubscribeButton"

                        Text="<%$Resources:wss,ToolBarMenuItemAlertMe%>"

                        Description="<%$Resources:wss,ToolBarMenuItemAlertMeDescription%>"

                        PermissionsString="CreateAlerts"

                        PermissionContext="CurrentList"

                        PermissionMode="Any"

                        MenuGroupId="500"

                        Sequence="500"

                        ImageUrl="/_layouts/images/MenuAlert.gif"

                        UseShortId="true"

                        runat="server"/>

                  <SharePoint:MenuItemTemplate

                        ID="AddToMyLinksButton"

                        Text="<%$Resources:wss,ToolBarMenuItemAddToMyLinks%>"

                        MenuGroupId="500"

                        Sequence="600"

                        UseShortId="true"

                        runat="server"/>

            </SharePoint:FeatureMenuTemplate>

      </Template>

</SharePoint:RenderingTemplate>

Not all the menu Item from this template are rendered to all the list. Based on the List type and the Permission Context, SharePoint renders the different “MenuItemtemplate” in the actions menu for the different list. When it finds that the List is not based on the List TemplateType "106" then it restricts the MenuItem template with ID “OfflineButton” (highlighted above) which renders the connect to outlook option.

So, how it has been done ? Who is doing this ? How can I Override this ?

The answers follows ……

It has been done through the “ActionsMenu” web control. In Microsoft.SharePoint.WebControls namespace you can find the “ActionsMenu” class which has the overridable methods like AddMenuItems(),AddMenuItem() and the SetmenuItemProperties(). The AddMenuItems() method calls the AddMenuItem() and adds every menu item under the ActionsMenu in the toolbar. But the SetmenuItemProperties() sets the property of this individual menuitem. In this method the “OfflineButton” menuitem’s visible property is set to false if the TemplateType is not equal to “106”. So the moral of the story is that you need to override this “SetmenuItemProperties()” method. But if you override and didn’t call the base method then all the MenuItem from the Template will be rendered along with your Connect to outlook option and as well you need to set the other properties like ClientOnClickScript() as well to integrate with the outlook properly.

So, What’s next… The following code tells you the story… code is self explanatory

public class CustomOffline:ActionsMenu

    {

        MenuItemTemplate myItem = null;

       

        protected override void SetMenuItemProperties()

        {

            base.SetMenuItemProperties();

            myItem = this.GetMenuItem("OfflineButton"); // Get the “OfflineButton” menu item from the template

            // Set all the required properties to integrate with the outlook, especially ClientOnClickScript

            Page.ClientScript.RegisterClientScriptBlock(typeof(ActionsMenu), "offline_button_js", "" +

    "<script language=\"JavaScript\">\n<!--\n" +

    "var offlineBtnText = GetStssyncAppNameForType('" +

        "Calendar" + "','" + SPResource.GetString(Strings.ToolBarMenuItemOfflineDefaultText) + "');\n" +

    "var offlineBtnImg = GetStssyncIconPath('', '/_layouts/images/menu');\n" +

    "//-->\n</script>\n");

         

            string webUrl = SPHttpUtility.EcmaScriptStringLiteralEncode(

                             SPHttpUtility.UrlPathEncode(Web.Site.MakeFullUrl(List.ParentWebUrl),/*allow hash*/false));

            string webName = SPHttpUtility.EcmaScriptStringLiteralEncode(Web.Title);

            string guid = SPHttpUtility.EcmaScriptStringLiteralEncode("{"+List.ID+"}");

            string listName = SPHttpUtility.EcmaScriptStringLiteralEncode(List.Title);

          

            SPViewContext oViewContext = SPContext.Current.ViewContext;

            SPView oView = SPContext.Current.List.Views[oViewContext.ViewId];

            string viewUrl = SPHttpUtility.EcmaScriptStringLiteralEncode(

                            SPHttpUtility.UrlPathEncode(Web.ServerRelativeUrl,/*allow hash*/false)) + "" + @"\u002f" + SPHttpUtility.EcmaScriptStringLiteralEncode(

                            SPHttpUtility.UrlPathEncode(oView.Url.Remove(oView.Url.LastIndexOf(@"/")),/*allow hash*/false));

            string listUrl = SPHttpUtility.EcmaScriptStringLiteralEncode(

                 SPHttpUtility.UrlPathEncode(Web.ServerRelativeUrl,/*allow hash*/false)) + "" + @"\u002f" + SPHttpUtility.EcmaScriptStringLiteralEncode(

                            SPHttpUtility.UrlPathEncode(oView.Url.Remove(oView.Url.LastIndexOf(@"/")),/*allow hash*/false));

            string folderParams = "";//"true" +

                //"','" + SPContext.Current.List.RootFolder.Url +

               // "','" + SPContext.Current.List.RootFolder.UniqueId.ToString() + "'";

            myItem.ClientOnClickScript =

                    "javaScript:ExportHailStorm(" +

                    "'" + "Calendar" + "'," +

                    "'" + webUrl + "'," +

                    "'" + guid + "'," +

                    "'" + webName + "'," +

                    "'" + listName + "'," +

                    "'" + viewUrl + "',''," +

                    "'" + listUrl + folderParams + "');";

            myItem.Visible = true;

            myItem.Sequence = 100;

            myItem.ImageScript = "javascript:offlineBtnImg";

            myItem.TextScript = "javascript:offlineBtnText";

            myItem.HiddenScript = "!offlineBtnText";

           

            // After setting all the properties then add the menuitem by calling the AddmenuItem method. Eventhough we are setting the visible property to false the base method overrides it. So it is mandatory to add the item again with the respective properies.

            AddMenuItem("CustomOfflineButton", "Connect to Outlook", myItem.ImageUrl, "Synchronize items and make them available offline", myItem.ClientOnClickNavigateUrl, myItem.ClientOnClickScript);

        }

     

    }

Build the DLL and deploy in the GAC. So far so good… Now how to render the CustomActionsMenu web control instead of the OOB ActionsMenu web control and of course in the supported way.

Continue reading ….

Create a custom “Defaulttemplates.ascx” control with a rendering template which consists your CustomActionsMenu control. Add the TagPrefix for the assembly built and render the CustomActionsMenu control in the place of OOB ActionsMenu control. The custom DefaultTemplates.ascx looks like follows :

<%@ Control Language="C#" AutoEventWireup="false" %>

<%@Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>

<%@Register TagPrefix="CustomActionMenu" Assembly="CustomActionMenu, Version=1.0.0.0, Culture=neutral, PublicKeyToken=29dc8669497c273e" namespace="CustomActionMenu"%>

<%@Register TagPrefix="SPHttpUtility" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.Utilities"%>

<%@ Register TagPrefix="wssuc" TagName="ToolBar" src="~/_controltemplates/ToolBar.ascx" %>

<%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>

<SharePoint:RenderingTemplate ID="CalendarViewToolbar" runat="server">

      <Template>

            <wssuc:ToolBar CssClass="ms-menutoolbar" EnableViewState="false" id="toolBarTbl" ButtonSeparator="<img src='/_layouts/images/blank.gif' alt=''>" RightButtonSeparator="&nbsp;&nbsp;" runat="server">

                  <Template_Buttons>

                        <SharePoint:NewMenu ID="NewMenu1" AccessKey="<%$Resources:wss,tb_NewMenu_AK%>" runat="server" />

                        <CustomActionMenu:CustomOffline ID="ActionsMenu1" AccessKey="<%$Resources:wss,tb_ActionsMenu_AK%>" runat="server" TemplateName="ToolbarActionsMenu" />

                        <SharePoint:SettingsMenu ID="SettingsMenu1" AccessKey="<%$Resources:wss,tb_SettingsMenu_AK%>" runat="server" />

                  </Template_Buttons>

                  <Template_RightButtons>

                        <SharePoint:PagingButton ID="PagingButton1" runat="server"/>

                        <SharePoint:ListViewSelector ID="ListViewSelector1" runat="server"/>

                  </Template_RightButtons>

            </wssuc:ToolBar>

      </Template>

</SharePoint:RenderingTemplate>

Note : You can find that the TemplateName property of the CustomActionsmenu control reads the menuitems from the provided rendering template (“ToolBarActionsMenu”). If you want to hide something in your CustomActionsMenu then you can just write your own template with the menuItems in the custom defaulttemplates.ascx and can mention the ID of the template in the TemplateName property.

Now, how the list definition knows that it should render the “CalendarViewToolBar” template. For that, explicitly provide the ToolBarTemplate name in the every view of the list definition in the schema.xml file.

Following is the sample for the AllItems view, make this change to every view so that every view renders the CustomActionsmenu in the toolbar.

      <View BaseViewID="1" Type="HTML" ToolbarTemplate="CalendarViewToolbar" WebPartZoneID="Main" DisplayName="$Resources:core,userinfo_schema_alleventsview;" SetupPath="pages\viewpage.aspx" ImageUrl="/_layouts/images/events.png" Url="AllItems.aspx" DefaultBaseView="TRUE">

Install and activate your custom calendar list definition. Create a list based on your custom calendar template and browse to the list and check your “CustomActionsMenu” rendered with the Connecttooutlook feature.

Please leave your comments if you have any other findings in the Custom calendar list definition.