blog.scoreman.net

Posts Tagged ‘SharePoint’

InfoPath error after installing SharePoint 2010 Service Pack 2

Tuesday, October 8th, 2013

Interesting discovery yesterday that I thought I should share. After installing SharePoint 2010 Service pack 2 a customer ran into problems with their InfoPath forms. The generic error message was “The custom code in the form cannot be run. This functionality may be deactivated on the server”. Looking in the ULS log there were some more information:

Microsoft.SharePoint.UserCode.SPUserCodeSolutionProxiedException: Could not load type 'Microsoft.SharePoint.Administration.SPService' from assembly 'Microsoft.SharePoint, Version=14.900.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c'.    Server stack trace:     
 at Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.QueryDataOnLoad(DataAdapter documentDataAdapter, DataObject documentDataObject)    
 at Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.ExecuteInitOnLoadForDataObjects()    
 at Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.LoadFromRemoteContext(Boolean firstOpened, String editingSessionId, Solution solution, Byte[] serializedState, Byte[] serializedVersionState, Dictionary`2 inputParams, OpenParameters openParameters)

After a lot of trial and errors I did some reflection on the Microsoft.Office.InfoPath.Server.DocumentLifetime.Document.QueryDataOnLoad method in Microsoft.Office.InfoPath.Server.dll. The method had a small code change between the Cumulative Update the customer was on and Service Pack 2.

Before Service Pack 2

Before Service Pack 2

After Service Pack 2

After Service Pack 2

The small code change, FormsService formsService = FormsService.TryGetLocal(), uses Microsoft.SharePoint.Administration.SPService. The problem occurs when this code is run from within the sandbox process. Then SPService is not available just like the error message said. QueryDataOnLoad gets called if you have an InfoPath form with data connections that loads on startup.

It is really easy to reproduce this bug. Just install SP2, create an InfoPath form with a data connection (that loads a SharePoint list at startup) and also add code-behind for the loading event. Fortunately the line of code causing the problem is removed in August 2013 Cumulative Update.

Aggregating tasks using SharePoint Search REST API

Tuesday, August 20th, 2013

This is a short example of how you can use SharePoint Search REST Search to aggregate all tasks assigned to the current user that are not set to completed. The example is a SharePoint-hosted app that makes two REST calls. The first one is for retrieving the full name of the user currently logged in. The second call is to the search API and executes the query. For this app to Work you will have to add QueryAsUserIgnoreAppPrincipal permisson.

For the filtering of all tasks, except the ones with status set to completed, to Work the crawled properties ows_Status will have to be added to the managed property Status. If you want to list all tasks regardless of status just remove “NOT Status:Completed”.

'use strict';

jQuery(document).ready(function () {
    getCurrentUserDisplayName().then(getUserTasks).then(displayResult);
});

function getCurrentUserDisplayName() {
    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/web/currentuser";
    return jQuery.ajax(url, { method: "GET", headers: { "accept": "application/json;odata=verbose" } });
}

function getUserTasks(data) {
    var currentUserDisplayName = data.d.Title;
    var url = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?selectproperties='Title,Path'&querytext='ContentTypeId:0x0108* NOT Status:Completed AND AssignedTo:" + currentUserDisplayName + "'";
    return jQuery.ajax(url, { method: "GET", headers: { "accept": "application/json;odata=verbose" } });
}

function displayResult(data) {
    var viewModel = function () {
        var self = this;
        self.tasks = ko.observableArray();

        jQuery.each(data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results, function () {
            self.tasks.push({
                title: ko.observable(getValueByKey('Title', this.Cells.results)),
                url: ko.observable(getValueByKey('Path', this.Cells.results))
            });
        });
    };

    ko.applyBindings(new viewModel());
}

function getValueByKey(key, results) {
    var postItem = jQuery.grep(results, function (e) {
        if (e.Key === key)
            return e;
    })[0].Value;

    return postItem;
}

In displayResult I’m using Knockout JavaScript library to bind the result to my UI but you are free to do whatever you you want with the result. Thanks to Cas van Lersel for the helper function getValueByKey that parses the key value pairs that are returned by SharePoint.

SharePoint 2010 Foundation vs. Server

Wednesday, May 12th, 2010

Interested in what features are included in SharePoint 2010 Foundation and what’s not included. This is a really good summary:

http://www.fpweb.net/sharepoint-hosting/2010/features/foundation-vs-server.asp

Week numbers in SharePoint monthly calendar view

Tuesday, June 23rd, 2009

For some organizations working with week number is very important. Although you can turn on showing week numbers in the Date Navigator under Regional Settings there will be no week numbers showing in the monthly view of the calendar. My goal was to have week numbers printed like in the image below.

This is how I did it.

Step 1: Override CalendarViewmonthChrome template

SharePoint uses different templates to render the different views(day, week, month) of a calendar. In order to change the way the monthly view gets rendered you need to add a custom ascx file to the CONTROLTEMPLATES folder i the 12-hive. This file needs to override the CalendarViewmonthChrome rendering template. What I have done is to copy the default rendering template and replaced the MonthlyCalenderView control with my own MyMonthlyCalendarView.

<%@ 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="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" %>
<%@ Register TagPrefix="myControls" Namespace="MyNamespace" Assembly="MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXXXXXXX" %>
<SharePoint:RenderingTemplate ID="CalendarViewmonthChrome" runat="server">
  <Template>
    <div id=MontlyViewDefault_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","")%>">
    <input type=hidden id=ExpandedWeeksId name=ExpandedWeeks value="">
    <table border=0 width=100% id="CalViewTable1" style="border-collapse: collapse"  cellpadding=0>
      <tr><td><IMG SRC="/_layouts/images/blank.gif" width=742 height=1 alt=""></td></tr>
      <tr>
         <td>
         <table border="0" width="100%" cellspacing="1" cellpadding="0" id="CalViewTable12" style="border-collapse: collapse">
          <tr>
            <td nowrap>
              <div nowrap>
                <a href="javascript:MoveToViewDate('<%# DataBinder.Eval(Container,"PreviousDate","") %>', null);" 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_prevmonth%>' EncodeMethod='HtmlEncode'/>" ></a>
                 <a href="javascript:MoveToViewDate('<%# DataBinder.Eval(Container,"NextDate","") %>', null);" 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_nextmonth%>' EncodeMethod='HtmlEncode'/>" ></a>
                &nbsp;<%# DataBinder.Eval(Container,"HeaderDate","") %>&nbsp;
               </div>
            </td>
            <td>&nbsp;</td>
            <tdDirection","")%>">
              <span id=ExpandAllId dir="<%# DataBinder.Eval(Container,"Direction","")%>">
                <a href="javascript:" onclick="javascript:GetMonthView('1111111');return false;" tabindex=1 accesskey="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_expandall_AK%>' EncodeMethod='HtmlEncode'/>" nowrap ><NOBR><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,calendar_expandall%>" EncodeMethod='HtmlEncode'/></NOBR></a>
              </span>
              &nbsp;
              <span id=CollapseAllId dir="<%# DataBinder.Eval(Container,"Direction","")%>">
                <a href="javascript:" onclick="javascript:GetMonthView('0000000');return false;" tabindex=1 accesskey="<SharePoint:EncodedLiteral runat='server' text='<%$Resources:wss,calendar_collapseall_AK%>' EncodeMethod='HtmlEncode'/>" nowrap ><NOBR><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,calendar_collapseall%>" EncodeMethod='HtmlEncode'/></NOBR></a>
              </span>
              <span> &nbsp;|</span>
              <Sharepoint:SPCalendarTabs runat="server"
              SelectedViewTab='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ViewType","")) %>'
              ListName='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ListName","")) %>'
              ViewGuid='<%# SPHttpUtility.HtmlEncode(DataBinder.Eval(Container,"ViewName","")) %>'
              >
              </Sharepoint:SPCalendarTabs>
            </td>
          </tr>
        </table>
         </td>
      </tr>
      <tr>
        <td>
          <myControls:MyMonthlyCalendarView runat="server"
          SelectedDate='<%# DataBinder.Eval(Container,"SelectedDate","") %>'
          ExpandedWeeks='<%# SPHttpUtility.HtmlEncode( DataBinder.Eval(Container,"ExpandedWeeks","")) %>'
          ItemTemplateName="CalendarViewMonthItemTemplate"
          ItemAllDayTemplateName="CalendarViewMonthItemAllDayTemplate"
          ItemMultiDayTemplateName="CalendarViewMonthItemMultiDayTemplate"
          TabIndex=2
          >
          </myControls:MyMonthlyCalendarView>
        </td>
      </tr>
     </table>
    </div>
  </Template>
</SharePoint:RenderingTemplate>

Step 2: Intercepting and rewriting html output

The rendering of the table cell where I wanted to insert the week number is well hidden in the MonthlyCalendarView control. What I did instead was to override the AppendEmptyTD and AppendEventTD methods and checked if it was the first day in the week. If so I knew that the StringBuilder object would contain some html with an empty image tag that had an alt-attribute containing text for the week span. Using a regular expression I replaced the image tag with the week number for the current date. Notice that the function that gets the week number is somewhat hard coded and could be rewritten so that Regional Settings for the SPWeb is taken into account.


public class MyMonthlyCalendarView : MonthlyCalendarView
{
    private static Regex weekRegex = new Regex(@"<img border=0 src='/_layouts/images/blank.gif' class='ms-cal-blankimage' alt='[a-z]+s[0-9]{2}s-s[a-z]+s[0-9]{2}'>", RegexOptions.IgnoreCase | RegexOptions.Multiline);

    protected override void AppendEmptyTD(ref StringBuilder str, int iday, Microsoft.SharePoint.Utilities.SimpleDate currDateInWeek)
    {
        if (iday == 0)
        {
            this.AppendWeekNumber(ref str, currDateInWeek);
        }
        base.AppendEmptyTD(ref str, iday, currDateInWeek);
    }

    protected override void AppendEventTD(ref StringBuilder str, int iday, SPCalendarItemContainer oEvent, int colspan, int rowspan, Microsoft.SharePoint.Utilities.SimpleDate currDateInWeek, int tabIndex)
    {
        if (iday == 0)
        {
            this.AppendWeekNumber(ref str, currDateInWeek);
        }
        base.AppendEventTD(ref str, iday, oEvent, colspan, rowspan, currDateInWeek, tabIndex);
    }
   
    private void AppendWeekNumber(ref StringBuilder str, Microsoft.SharePoint.Utilities.SimpleDate currDateInWeek)
    {
        string content = str.ToString();         
        if (weekRegex.IsMatch(content))
        {               
            int week = GetWeekNumber(currDateInWeek);
            content = weekRegex.Replace(content, week.ToString());
            str = new StringBuilder(content);
        }
    }

    private static int GetWeekNumber(SimpleDate date)
    {
        CultureInfo culture = SPContext.Current.Web.Locale;
        return culture.Calendar.GetWeekOfYear(new DateTime(date.Year, date.Month, date.Day), CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
    }
}

Flush Cache for Publishing Pages

Thursday, April 16th, 2009

A while back I wrote some custom code that redirected the user directly to the edit mode of a publishing page. This was done by passing querystring parameters “ControlMode=Edit&DisplayMode=Design”. The only problem was that if the user had hit the page before the publishing console was cached and would not display the right buttons for edit mode. Using Reflector I found out that the Publishing Console uses a cache and that there where internal classes for managing the cache. With a little bit of reflection I could call into these classes and flush the cache.

private static void FlushItemCachedState(string page, SPSite site)
{
    Assembly assembly = Assembly.GetAssembly(typeof(PublishingPage));
    Type cacheManagerType = assembly.GetType("Microsoft.SharePoint.Publishing.CacheManager");
    MethodInfo miGetManager = cacheManagerType.GetMethod("GetManager", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance, null, new Type[] { typeof(SPSite) }, null);
    object manager = miGetManager.Invoke(null, new object[] { site });
    PropertyInfo piObjectFactory = cacheManagerType.GetProperty("ObjectFactory");
    object objectFactory = piObjectFactory.GetValue(manager, null);
    Type cacheObjectFactoryType = assembly.GetType("Microsoft.SharePoint.Publishing.CachedObjectFactory");
    MethodInfo miFlushItem = cacheObjectFactoryType.GetMethod("FlushItem", new Type[] { typeof(string) });
    string cacheKey = new Uri(page).LocalPath;
    miFlushItem.Invoke(objectFactory, new object[] { cacheKey });
}

CAML query with “Today” that includes time value

Tuesday, February 17th, 2009

I was trying to create a CAML query that would filter out all pages with a valid publishing date (and time) using the CrossListQueryInfo object. When I used the <Today/> element in the query it ignored the time.

I remembered reading some were that you could use <Now/> instead of <Today/> but that didn’t do it.

<Leq>
   <FieldRef Name="PublishingStartDate" Nullable="True" Type="DateTime"/>
   <Value Type="DateTime"><Now/></Value>
</Leq>

It turns out that you should use the <Today/> element but that you also need to add a IncludeTimeValue=TRUE attribute.

<Leq>
   <FieldRef Name="PublishingStartDate" Nullable="True" Type="DateTime"/>
   <Value Type="DateTime" IncludeTimeValue="TRUE"><Today/></Value>
</Leq>

Changing page layout and content type of a publishing page

Friday, February 6th, 2009

Yesterday i wrote to extension methods that helps changing page layout and content type of a publishing page. The first method finds the layout by name, sets the content type on the list item and changes the layout. The second method (EnsureContentTypeOnPagesList) ensures that the new content type will be added to the Pages library if not already present (Content types will be added to the Pages library first when you add a page using that content type).

public static void ChangePageLayout(this PublishingPage page, string layoutName)
{
    PageLayout[] pageLayouts = page.PublishingWeb.GetAvailablePageLayouts();
    PageLayout newLayout = pageLayouts.SingleOrDefault(p => p.Name == layoutName);
    if (newLayout != null)
    {
        page.PublishingWeb.EnsureContentTypeOnPagesList(newLayout.AssociatedContentType);
        page.ListItem[SPBuiltInFieldId.ContentTypeId] = newLayout.AssociatedContentType.Id;
        page.Layout = newLayout;
        page.ListItem.SystemUpdate();
    }
}
public static void EnsureContentTypeOnPagesList(this PublishingWeb publishingWeb, SPContentType contentType)
{
    SPContentType listContentType = publishingWeb.PagesList.ContentTypes.Cast<SPContentType>()
        .SingleOrDefault(ct => ct.Id.ToString().StartsWith(contentType.Id.ToString()));
    if (listContentType == null)
    {
        SPSecurity.RunWithElevatedPrivileges(delegate
        {
            using (var elevatedSite = new SPSite(publishingWeb.Web.Site.ID))
            {
                using (var elevatedWeb = elevatedSite.OpenWeb(publishingWeb.Web.ID))
                {
                    elevatedWeb.AllowUnsafeUpdates = true;
                    Guid listId = PublishingWeb.GetPagesListId(elevatedWeb);
                    elevatedWeb.Lists[listId].ContentTypes.Add(contentType);
                    elevatedWeb.AllowUnsafeUpdates = false;
                }
            }
        });
    }
}

Running SPDisposeCheck on Microsoft.*

Friday, February 6th, 2009

I found it interesting that SPDisposeCheck ignored files and namespaces that started with Microsoft and System. With a little bit of .net reflection I managed to come around the “problem”:

Microsoft.SharePoint.dll 9 varnings
Microsoft.Office.Policy.dll 1 varning
Microsoft.Office.Server.Search.dll 1 varning
microsoft.sharepoint.portal.dll 2 varnings
Microsoft.SharePoint.Publishing.dll 10 varnings
Microsoft.SharePoint.Search.dll 1 varning

Using Telerik Image/Asset Picker to choose images in publishing pages

Friday, February 6th, 2009

Telerik is a great third party tools for providing the SharePoint user with a richer toolbar when editing rich html fields. It has features for resizing and cropping images as well as a much easier way to navigate when selecting images. What I wanted to do was to use this image picker outside the context of the toolbar. I wanted the image picker to pop up when you click on Edit Picture in a MOSS publishing page that had an image in the page layout.

The way I implemented it was just like a regular publishing field control that could be put on the publishing page and save the image information to the page’s metadata.

Step 1: Custom rendering template for the control

First of we need to have a rendering template for the control. This is put in a ascx-file in the CONTROLTEMPLATES folder in the 12-hive. The control have a Telerik DialogOpener and some html to make it look like the standard publising image field.

<%@ Control Language="C#" Debug="true" %>
<%@ 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="telerik" Namespace="Telerik.Web.UI" Assembly="Telerik.Web.UI, Version=2008.3.1125.20, Culture=neutral, PublicKeyToken=121fae78165ba3d4" %>
<SharePoint:RenderingTemplate ID="TelerikImageField" runat="server">
    <Template>
        <telerik:dialogopener
            HandlerUrl="/_wpresources/RadEditorSharePoint/5.3.1.0__1f131a624888eeed/Resources/Telerik.Web.UI.DialogHandler.aspx"
            runat="server" id="dialogOpener">
        </telerik:dialogopener>       
        <div height="100%" width="100%" style="padding:4px">
            <div width="100%">               
        <div>
            <asp:HyperLink ID="insertImagePictureLink" NavigateUrl="#" TabIndex="-1" runat="server"><asp:Image ID="insertImagePicture" ImageUrl="/_layouts/1033/IMAGES/rteimg.gif" BorderWidth="0" runat="server" /></asp:HyperLink><asp:HyperLink ID="insertImageTextLink" NavigateUrl="#" runat="server" />
        </div>
        <div id="divClearImage" runat="server">
            <asp:HyperLink ID="clearImagePictureLink" NavigateUrl="#" TabIndex="-1" runat="server"><asp:Image ID="clearImagePicture" ImageUrl="/_layouts/IMAGES/CMSRemoveImage.GIF" BorderWidth="0" runat="server" /></asp:HyperLink><asp:HyperLink ID="clearImageTextLink" NavigateUrl="#" runat="server" />
        </div>       
            </div>
        </div>              
        <div id="divImageContent" runat="server" />
        <div  id="divEmptyPanel" runat="server">
            <div height="100%" width="100%" style="padding:4px" align="center" valign="center">
                <asp:HyperLink ToolTip="InsertButtonTooltip" ID="emptyPanelLink" NavigateUrl="#" CssClass="ms-toolbar ms-selectorlink" runat="server" />
            </div>
        </div>
        <input id="hiddenContent" type="hidden" runat="server" />
    </Template>
</SharePoint:RenderingTemplate>

Step 2: Implement the Code Behind for the control

I’m not going to to through the hole code but basically what it does is to initialize the Telerik DialogOpener, registers JavaScript functions for opening the dialog and handling the result it returns.

public class TelerikImageField : BaseFieldControl
{
    protected DialogOpener dialogOpener;
    protected HtmlGenericControl divImageContent, divEmptyPanel, divClearImage;
    protected HtmlInputHidden hiddenContent;
    protected HyperLink insertImagePictureLink, insertImageTextLink, clearImagePictureLink, clearImageTextLink, emptyPanelLink;
    protected Image insertImagePicture, clearImagePicture;
    private readonly string telerikContentProviderName = "Telerik.SharePoint.Editor.SPContentProvider, RadEditorSharePoint, Version=5.3.1.0, Culture=neutral, PublicKeyToken=1f131a624888eeed";
   
    protected override string DefaultTemplateName
    {
        get
        {
            return "TelerikImageField";
        }
    }
    public override object Value
    {
        get
        {
            EnsureChildControls();
            if (!string.IsNullOrEmpty(hiddenContent.Value))
            {
                return hiddenContent.Value;
            }
            else
            {
                return null;
            }
        }
        set
        {
            EnsureChildControls();
            if (value != null)
            {
                var image = value as ImageFieldValue;
                divImageContent.InnerHtml = image.ToString();
                hiddenContent.Value = image.ToString();
                divClearImage.Attributes["class"] = "ms-toolbarItem ms-selectorlink";
                divEmptyPanel.Style[HtmlTextWriterStyle.Display] = "none";
            }               
        }
    }
    protected override void CreateChildControls()
    {
        if (Field == null)
        {
            return;
        }
        if (ControlMode == SPControlMode.Display)
        {
            return;
        }
        base.CreateChildControls();
        this.InitControls();
        this.CreateDialogParameters();
        this.CreateClientScripts();
        this.SetResources();
        divEmptyPanel.Style.Add(HtmlTextWriterStyle.Display, "inline");
        divClearImage.Attributes.Add("class", "ms-toolbarItem ms-selectorlink ms-selectorlinkdis");
        insertImagePictureLink.Attributes.Add("onclick", string.Format("$find('{0}').open('ImageManager');return false;", dialogOpener.ClientID));
        insertImageTextLink.Attributes.Add("onclick", string.Format("$find('{0}').open('ImageManager');return false;", dialogOpener.ClientID));
        emptyPanelLink.Attributes.Add("onclick", string.Format("$find('{0}').open('ImageManager');return false;", dialogOpener.ClientID));
        clearImagePictureLink.Attributes.Add("onclick", "ImageManagerClear();return false;");
        clearImageTextLink.Attributes.Add("onclick", "ImageManagerClear();return false;");
    }
    private void SetResources()
    {
        Assembly assembly = Assembly.Load("Microsoft.SharePoint.Publishing.intl, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c");
        ResourceManager rm = new ResourceManager("Microsoft.SharePoint.Publishing.Strings", assembly);
       
        insertImagePicture.AlternateText = rm.GetString("FieldSelectorControlsImageInsertButtonTooltip", Web.Locale);
        insertImageTextLink.ToolTip = rm.GetString("FieldSelectorControlsImageInsertButtonTooltip", Web.Locale);
        insertImageTextLink.Text = rm.GetString("FieldSelectorControlsImageInsertButtonText", Web.Locale);
        clearImagePicture.AlternateText = rm.GetString("FieldSelectorControlsClearAssetButtonText", Web.Locale);
        clearImageTextLink.ToolTip = rm.GetString("FieldSelectorControlsClearAssetButtonText", Web.Locale);
        clearImageTextLink.Text = rm.GetString("FieldSelectorControlsClearAssetButtonText", Web.Locale);
        emptyPanelLink.ToolTip = rm.GetString("FieldSelectorControlsImageInsertButtonTooltip", Web.Locale);
        emptyPanelLink.Text = rm.GetString("FieldSelectorControlsImageAddPromptLinkText", Web.Locale);
    }
    private void InitControls()
    {
        dialogOpener = FindAndValidateControl("dialogOpener") as DialogOpener;
        divImageContent = FindAndValidateControl("divImageContent") as HtmlGenericControl;
        hiddenContent = FindAndValidateControl("hiddenContent") as HtmlInputHidden;
        insertImagePictureLink = FindAndValidateControl("insertImagePictureLink") as HyperLink;
        insertImageTextLink = FindAndValidateControl("insertImageTextLink") as HyperLink;
        insertImagePicture = FindAndValidateControl("insertImagePicture") as Image;
        clearImagePicture = FindAndValidateControl("clearImagePicture") as Image;
        clearImagePictureLink = FindAndValidateControl("clearImagePictureLink") as HyperLink;
        clearImageTextLink = FindAndValidateControl("clearImageTextLink") as HyperLink;
        emptyPanelLink = FindAndValidateControl("emptyPanelLink") as HyperLink;
        divEmptyPanel = FindAndValidateControl("divEmptyPanel") as HtmlGenericControl;
        divClearImage = FindAndValidateControl("divClearImage") as HtmlGenericControl;
    }
    private void CreateClientScripts()
    {
        ScriptManager scriptManager = ScriptManager.GetCurrent(this.Page);
        string script = @"
            function ImageManagerInsert(sender, args)  
            {  
                var selectedItem = args.SelectedItem;  
                var resultImageObject = args.Result;                       
                var divContent = $get('" + divImageContent.ClientID + @"');  
                var divEmptyPanel = $get('" + divEmptyPanel.ClientID + @"');  
                var hiddenContent = $get('" + hiddenContent.ClientID + @"');  
                var divClearImage = $get('" + divClearImage.ClientID + @"');  
                divEmptyPanel.style.display = 'none';
                divContent.style.display = 'inline';
               
                var parentCssClass = divClearImage.className;
                var myRegex=new RegExp("" ms-selectorlinkdis"", ""ig"");
                parentCssClass = parentCssClass.replace(myRegex, """");
                divClearImage.className = parentCssClass;
                if (document.all)  
                {  
                    divContent.innerHTML = resultImageObject.outerHTML;  
                    hiddenContent.value = resultImageObject.outerHTML;  
                }  
                else  
                {  
                    divContent.innerHTML = ""<img src='"" +  selectedItem.getPath() + ""' />"";  
                    hiddenContent.value = ""<img src='"" +  selectedItem.getPath() + ""' />"";  
                }  
            }
            function ImageManagerClear(sender)  
            {  
                var divContent = $get('" + divImageContent.ClientID + @"');  
                var divEmptyPanel = $get('" + divEmptyPanel.ClientID + @"');  
                var hiddenContent = $get('" + hiddenContent.ClientID + @"');
                var divClearImage = $get('" + divClearImage.ClientID + @"');     
                  
                divContent.innerHTML = '';  
                divContent.style.display = 'none';
                hiddenContent.value = '';                                     
                divEmptyPanel.style.display = 'inline'; 
                divClearImage.className = divClearImage.className + ' ms-selectorlinkdis'; 
            } 
        ";
        ScriptManager.RegisterClientScriptBlock(this, this.GetType(), string.Concat("TelerikImageField_", this.ClientID), script, true);
    }
    private void CreateDialogParameters()
    {
        string[] paths = new string[] { "PublishingImages", "/SiteCollectionImages" };
        string siteUrl = SPContext.Current.Site.Url;
        string webUrl = SPContext.Current.Web.ServerRelativeUrl;
        string webId = string.Empty;
        FileManagerDialogParameters imageManagerParameters = new FileManagerDialogParameters();
        imageManagerParameters.ViewPaths = paths;
        imageManagerParameters.UploadPaths = paths;
        imageManagerParameters.DeletePaths = paths;
        imageManagerParameters.MaxUploadFileSize = 5000000;
        imageManagerParameters.FileBrowserContentProviderTypeName = telerikContentProviderName;
        imageManagerParameters.Add("SiteUrl", siteUrl);
        imageManagerParameters.Add("WebUrl", webUrl);
        imageManagerParameters.Add("WebID", webId);
                   
        DialogDefinition imageManager = new DialogDefinition(typeof(ImageManagerDialog), imageManagerParameters);
        imageManager.ClientCallbackFunction = "ImageManagerInsert";
        imageManager.Width = Unit.Pixel(694);
        imageManager.Height = Unit.Pixel(440);
        dialogOpener.DialogDefinitions.Add("ImageManager", imageManager);
        FileManagerDialogParameters imageEditorParameters = new FileManagerDialogParameters();
        imageEditorParameters.ViewPaths = paths;
        imageEditorParameters.UploadPaths = paths;
        imageEditorParameters.DeletePaths = paths;  
        imageEditorParameters.MaxUploadFileSize = 5000000;
        imageEditorParameters.FileBrowserContentProviderTypeName = telerikContentProviderName;
        imageEditorParameters.Add("SiteUrl", siteUrl);
        imageEditorParameters.Add("WebUrl", webUrl);
        imageEditorParameters.Add("WebID", webId);
        DialogDefinition imageEditor = new DialogDefinition(typeof(ImageEditorDialog), imageEditorParameters);
        imageEditor.Width = Unit.Pixel(832);
        imageEditor.Height = Unit.Pixel(520);
        dialogOpener.DialogDefinitions.Add("ImageEditor", imageEditor);
    }
    protected virtual Control FindAndValidateControl(string id)
    {
        Control ctrl = TemplateContainer.FindControl(id);
        if (ctrl == null)
            throw new ArgumentException(string.Format("{0} is null. Corrupted ascx file.", id));
        return ctrl;
    }
}

Step 3: Modifying the page layout

As a last step you just need to change the page layout. Instead of this:

<PublishingWebControls:RichImageField id="ContentQueryImage" FieldName="PublishingRollupImage" AllowHyperLinks="false" runat="server"/>

You change it to this:

<myControls:TelerikImageField ID="RichImageField1" FieldName="PublishingRollupImage" runat="server" />

The final result looks like this:

Using MOSS internal resources

Thursday, January 29th, 2009

Sometimes you may want to use standard MOSS resource strings that are not found in .resx files in the 12-hive or wwwroot. These strings can reside as compiled resources inside the SharePoint assemblies. Here are two helper functions to extract those resource strings.

private static string publishingAssemblyString = "Microsoft.SharePoint.Publishing.intl, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c";
private static string officeServerAssemblyString = "Microsoft.Office.Server.intl, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c";

public static string GetPublishingResource(CultureInfo info, string key)
{
    Assembly assembly = Assembly.Load(publishingAssemblyString);
    ResourceManager rm = new ResourceManager("Microsoft.SharePoint.Publishing.Strings", assembly);
    return rm.GetString(key, info);
}

public static string GetOfficeServerResource(CultureInfo info, string key)
{
    Assembly assembly = Assembly.Load(officeServerAssemblyString);
    ResourceManager rm = new ResourceManager("Microsoft.Office.Server.Strings", assembly);
    return rm.GetString(key, info);
}