Sunday, February 7, 2010

A custom rendering template for the Calendar View control

Q: How do I create a custom rendering template that only affects one calendar view on the site?

A: In Microsoft Office SharePoint Server 2007 and WSS 3.0 it is possible to use a custom view style with the SPCalendarView control, so that additional views or replacements for the default views (Day, Week, Month) can be rendered by a custom RenderingTemplate.

This functionality is provided by using the undocumented SPCustomViewElement element definition, which may be used to create a custom view feature at the web level, that it turn points to the custom rendering template, e.g.:

<?xml version="1.0" encoding="utf-8"?>

<Solution xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" SolutionId="453b1767-713e-4ca2-80bb-33aa0b40348e" xmlns="http://schemas.microsoft.com/sharepoint/">

  <FeatureManifests>

    <FeatureManifest Location="HubKey.SharePoint\feature.xml" />

  </FeatureManifests>

</Solution>

<?xml version="1.0" encoding="utf-8" ?>

<Feature  Id="EE647B50-1408-4ac7-9B8F-27D86A2E8985"

          Title="HubKey Calendar View Feature"

          Description="Adds calendar custom view."

          Version="1.0.0.0"

          Creator="http://www.hubkey.com"

          ActivateOnDefault="True"

          Scope="Web"

          xmlns="http://schemas.microsoft.com/sharepoint/">

  <Properties>

    <Property Key="GloballyAvailable" Value="true" />

  </Properties>

    <ElementManifests>

        <ElementManifest Location="elements.xml" />

    </ElementManifests>

</Feature>

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

    <CustomView

        Title="Work Week" 

        Type="workweek" 

        ListType="Events" 

        ListViewType="CALENDAR" 

        Sequence="0" 

        AccessKey="w" 

        ImageHeight="15"

        ImageWidth="15"

        ImageName="week.gif"

        ViewChromeTemplateId="CustomCalendarViewweekChrome">

    </CustomView>

</Elements>



Although this functionality is native to MOSS and WSS 3.0, the definition for SPCustomViewElement may have been omitted from the wss.xsd schema. If this type is missing from the TEMPLATE\XML\wss.xsd file, the addition of a solution with the CustomView element will fail when verified against the schema. To avoid this scenario, the following type definition (highlighted in turquqoise) must be included in the wss schema file. Please note that editing the wss schema file cannot be recommended, please contact your Microsoft representative for more information.

<xs:complexType name="ElementDefinitionCollection">

        <xs:sequence>

            <xs:choice minOccurs="0" maxOccurs="unbounded">

                <xs:element name="ContentType" type="ContentTypeDefinition"/>

                <xs:element name="ContentTypeBinding" type="ContentTypeBindingDefinition"/>

                <xs:element name="DocumentConverter" type="DocumentConverterDefinition"/>

                <xs:element name="FeatureSiteTemplateAssociation" type="FeatureSiteTemplateAssociationDefinition"/>

                <xs:element name="Field" type="SharedFieldDefinition"/>

                <xs:element name="CustomAction" type="CustomActionDefinition"/>

                <xs:element name="CustomActionGroup" type="CustomActionGroupDefinition"/>

                <xs:element name="HideCustomAction" type="HideCustomActionDefinition"/>

                <xs:element name="Module" type="ModuleDefinition"/>

                <xs:element name="ListInstance" type="ListInstanceDefinition"/>

                <xs:element name="ListTemplate" type="ListTemplateDefinition"/>

                <xs:element name="Control" type="DelegateControlDefinition"/>

                <xs:element name="Receivers" type="ReceiverDefinitionCollection"/>

                <xs:element name="Workflow" type="WorkflowDefinition"/>

                <xs:element name="UserMigrator" type="UserMigratorDefinition"/>

                <xs:element name="CustomView" type="CustomViewDefinition"/>

            </xs:choice>

        </xs:sequence>

        <xs:attribute name="Id" type="UniqueIdentifier"/>

    </xs:complexType>

    <xs:complexType name="CustomViewDefinition" mixed="true">

        <xs:attribute name="ViewChromeTemplateId" type="xs:string"/>

        <xs:attribute name="ImageName" type="xs:string"/>

        <xs:attribute name="ImageWidth" type="xs:string"/>

        <xs:attribute name="ImageHeight" type="xs:string"/>

        <xs:attribute name="AccessKey" type="xs:string"/>

        <xs:attribute name="Sequence" type="Sequence"/>

        <xs:attribute name="ListViewType" type="xs:string"/>

        <xs:attribute name="ListType" type="xs:string"/>

        <xs:attribute name="Type" type="xs:string"/>

        <xs:attribute name="Title" type="LocalizableString"/>

    </xs:complexType>



The custom rendering template shown below is copied from the CalendarViewweekChrome template. Use DefaultTabsEnabled=false (highlighted in turquqoise) to replace the default calendar view tabs.

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

    <Template>

     <div id=CustomWeeklyViewDefault_CalendarView style="display:block; overflow:auto; width:<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ChromeWidth",""))%>; height:<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ChromeHeight",""))%>;"  dir="<%# DataBinder.Eval(Container,"Direction","")%>" >

      <table border=0 width=300 id="CalViewTable1" style="border-collapse: collapse" cellpadding=0>

            <tr><td class="ms-calheader" ><IMG SRC="/_layouts/images/blank.gif" width=742 height=1 alt=""></td></tr>

            <tr>

               <td class="ms-calheader">

               <table border="0" width="100%" cellspacing="1" cellpadding="0" id="CalViewTable12" style="border-collapse: collapse">

                    <tr>

                        <td nowrap>

                            <div class="ms-cal-navheader" nowrap>

                              <a href="javascript:MoveToDate('<%# DataBinder.Eval(Container,"PreviousDate","") %>');" tabindex=1 style="visibility:<%# DataBinder.Eval(Container,"PreviousDateVisible","")%>" accesskey="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_prev_AK%>' EncodeMethod='HtmlEncode'/>" >

                                <img border="0" src="/_layouts/images/prevbutton<%# DataBinder.Eval(Container,"Direction","")%>.gif" width="15" height="15" alt="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_prevweek%>' EncodeMethod='HtmlEncode'/>" ></a>

                              <a href="javascript:MoveToDate('<%# DataBinder.Eval(Container,"NextDate","") %>');" tabindex=1 style="visibility:<%# DataBinder.Eval(Container,"NextDateVisible","")%>" accesskey="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_next_AK%>' EncodeMethod='HtmlEncode'/>">

                                <img border="0" src="/_layouts/images/nextbutton<%# DataBinder.Eval(Container,"Direction","")%>.gif" width="15" height="15" alt="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_nextweek%>' EncodeMethod='HtmlEncode'/>" ></a>

                              &nbsp;<%# DataBinder.Eval(Container,"HeaderDate","") %>&nbsp;

                             </div>

                        </td>

                        <td>&nbsp;</td>

                        <td class="ms-cal-nav-buttons<%# DataBinder.Eval(Container,"Direction","")%>">

                          <Sharepoint:SPCalendarTabs ID="SPCalendarTabs1" runat="server" DefaultTabsEnabled=false

                            SelectedViewTab='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ViewType","")) %>'

                            ListName='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ListName","")) %>'

                            ViewGuid='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ViewName","")) %>'

                          >

                          </Sharepoint:SPCalendarTabs>

                        </>

                    </tr>

                </table>

               </td>

            </tr>

            <tr>

            <td>

                <Sharepoint:WeeklyCalendarView ID="WeeklyCalendarView1" runat="server" IsWorkWeek=true

                    SelectedDate='<%# DataBinder.Eval(Container,"SelectedDate","") %>'

                    ItemTemplateName="CalendarViewWeekItemTemplate"

                    ItemAllDayTemplateName="CalendarViewWeekItemAllDayTemplate"

                    ItemMultiDayTemplateName="CalendarViewWeekItemMultiDayTemplate"

                    TabIndex=2

                >

                </Sharepoint:WeeklyCalendarView>

            </td>

            </tr>

         </table>

    </div>

    </Template>

</SharePoint:RenderingTemplate>



The CalendarViewStyles element in the view’s Schema Xml can be used to set the default view, e.g.:

<CalendarViewStyles>

    <CalendarViewStyle Title=' Work Week' Type='workweek' Template='CustomCalendarViewweekChrome' Sequence='0' Default='TRUE'/>

    <CalendarViewStyle Title='Day' Type='day' Template='CalendarViewdayChrome' Sequence='1' Default='FALSE'/>

    <CalendarViewStyle Title='Week' Type='week' Template='CalendarViewweekChrome' Sequence='2' Default='FALSE'/>

    <CalendarViewStyle Title='Month' Type='month' Template='CalendarViewmonthChrome' Sequence='3' Default='FALSE'/>

</CalendarViewStyles>

Tuesday, June 30, 2009

Twitter Greasemonkey Following Script

Today Twitter rolled out some changes to the user interface on the “Following” and “Followers” sections of their website.

The following code is a Firefox Greasemonkey script for the new UI that identifies on the "Following" section, whether Twitter users you follow are following you in return.

For example, in the screen capture below it's easy to see that @lancearmstrong isn't following me yet.

Twitter friends

Click here to install the script (on Firefox with the Greasemonkey add-on installed), or save the code below as a text file named "twitterfriendsfollowing.user.js", and then drag the file onto your Firefox browser.

Update: Twitter updated the class name 'direct-message-able' to 'direct-messageable', which has been changed in the code below and downloadable script (above).

// ==UserScript==
// @name           Twitter Friends Following
// @namespace      greasemonkey.hubkey.com
// @description    Identifies whether Twitter users you follow are following you in return.
// @include        http://twitter.com/*following*
// @include        https://twitter.com/*following*
// @include        http://twitter.com/*friends*
// @include        https://twitter.com/*friends*
// ==/UserScript==
 
twitter_friends_following = {
    count: 0,
 
    identify: function() {
        var afollowers = document.getElementsByClassName('direct-messageable');
        for (var i = 0; i < afollowers.length; i++) {
            var avcard = afollowers[i].getElementsByClassName('about vcard');
            if (avcard.length != 1)
                continue;
            var node = document.createElement('span');
            node.setAttribute('class', 'is-following');
            node.innerHTML = '<i></i><strong>Following</strong>';
            avcard[0].appendChild(node);
        }
 
        try {
            twitter_friends_following.count = document.getElementsByClassName('direct-messageable').length;
        } catch (e) {
            twitter_friends_following.count = 0;
        }
    },
 
    monitor: function() {
        if (document.getElementsByClassName('direct-messageable').length != twitter_friends_following.count)
            twitter_friends_following.identify();
 
        setTimeout(twitter_friends_following.monitor, 200);
    }
};
 
setTimeout(twitter_friends_following.monitor, 200);

Tuesday, May 19, 2009

NAICS Code Lookup - SIC Code Finder for Dynamics CRM 4.0

We've been getting quite a few similar requests from our Microsoft Dynamics CRM clients, many of whom have expressed at an interest in improving the entry of NAICS and SIC codes for business users.

The solution we developed with was to generate custom entities that use picklists to simplify finding the correct codes. It works well - each custom entity contains all the current codes and is easily updatable when new codes are released. The entities write the codes or industry descriptions back to the parent entity (e.g. leads and accounts) for use in reporting and are of great help in developing targeted marketing lists. Each entity uses dependent picklists to narrow the code selection from macro sector to the full category code, making even the most specific ID easy to find. The picker is activated by the user double-clicking the code or code description. You can see the NACIS code lookup entity in action below. If you’d like to install this for your CRM organization, you can purchase the HK-NCP 2009 add-on directly from our web store (contact HubKey if you'd like more information). Alternatively, you could give it a bash yourself - comments section open below for anyone who gets stuck!