How to find correct javascript handler for OOB SharePoint ribbon button.

Hi all!

You clicked ribbon buttons a lot in SharePoint 2010. Sometimes, you as developer are interested in what code is executed when particular button is clicked. I’m going to show how you can easily find particular js handler for any ribbon button. For example, imagine you want to find what code is fires when you click “Edit HTML Source” drop down button in a rich text editor. First of all inspect this element using firebug, or any favorite browser’s dev tool.

Consider id attribute, for example Ribbon.EditingTools.CPEditTab.Markup.Html.Menu.Html.EditSource-Menu16. Next go to 14 hive and under TEMPLATE\GLOBAL\XML\ find cmdui.xml file. This file contains definition for all ribbon buttons in SharePoint. Search in this file by word Ribbon.EditingTools.CPEditTab.Markup.Html.Menu.Html.EditSource, you’ll find this definition.

This is definition for our button, and we are interested in Command attribute, which is equals to EditSource.

Next step is to search this command among SharePoint javascript files. Common architecture of ribbon handler involves javascript “classes” (essentially objects, javascript has no classes), which can handle particular command. Each class has canHandleCommand method. This method basically enumerate all commands which this class can handle and return true, if particular command name is in its list. So, search under 14\layouts using pattern *.js by word “EditSource”. You find several files, but it seems that SP.UI.Rte.debug.js is our file. Search inside this file and you can find that RTE.SPRichTextEditorComponentProvider is our class (“EditSource” command contains in an array inside init function). Find handleCommand method in this class (near 11328 line for me). In browser find this line and setup break, and then press “Edit HTML Source” to test it.

as you can see from screenshot above, breakpoint fire, $p0 parameter equals to “EditSource”, as expected. Next you can step into to find exact code, that will be fire:
this is RTE.RichTextEditor.editSource(). We found our handler! You can use this approach to find any other ribbon handlers, sometimes steps may differ, but I was trying to show common technique.

Hope this helps and good luck in spdevelopment!

How to force SharePoint to load *.debug.js versions of JavaScript files.

Hi all!

Sometimes during spdevelopment you may need to dig into OOB SharePoint javascript files and look how they work. As you may know, under layouts folder in 14 hive there are also debug versions of javascript files. When you are debugging you solution in visual studio by pressing F5 it might automatically replace standard js files with it debug versions, so you can set up breakpoint in OOB js files and try to debug. But what if you aren’t using F5 debugging, or want to force SharePoint to load debug versions in all site collections by default? You have two options here.

One option is to modify web.config for particular web application, so all sites under this web app will be automatically load debug versions of javascript files (and this is pretty cool for developer machine). You need to modify compilation tag and set attribute debug to true.

Another option is not to modify web.config, but to modify master page. Every SharePoint master page contains ScriptManager tag. It has ScriptMode attribute that is Auto by default (or if not presented). You can set it up to Debug.

Result will be the same as for web.config, but only for one particular site, where you customize master page. This should be sufficient, but if it is not working, try also modify web.config. And, of course, do it only on developer machine. 

Hope this tip helps and as usual good luck in spdevelopment!

SharePoint 2010 feature upgrade–upgrade pattern

Hi all! Today I’m going to show example of how to write clean and understandable code when using feature upgrade. Of course, solution which we are using is not perfect, but it rather solid, easy to use, easy to read, easy to extend. If you have any suggestions, improvements, or event better and cooler solution – you are welcome in comments :). Ok, lets start.

You are already know, that with sharepoint 2010 you can upgrade your features by adding this sample xml:

<UpgradeActions>
    <VersionRange BeginVersion="0.0.0.0" EndVersion="0.0.0.09">
      <CustomUpgradeAction Name="SomeActionName">
        <Parameters>
          <Parameter Name="TitlePrefix">Upgrade Time:</Parameter>
        </Parameters>
      </CustomUpgradeAction>
    </VersionRange>
</UpgradeActions>

CustomUpgradeAction is not the only allowed tag inside VersionRange, but I’m going to focus on it, because with this tag we can specify actions, which invokes by code. To use above action you need to specify upgrade actions receiver and override FeatureUpgrading  method. Very straightforward and simple implementation of this method for our above example can looks like this one:

public override void FeatureUpgrading(SPFeatureReceiverProperties properties, string upgradeActionName, System.Collections.Generic.IDictionary<string, string> parameters)
{
	switch (upgradeActionName)
	{
		case "SomeActionName":
			var web = properties.Feature.Parent as SPWeb;
			var list = web.Lists["TestUpgradeList"];
			var item = list.Items.Add();
			item["Title"] = parameters["TitlePrefix"] +  DateTime.Now.ToShortTimeString();
			item.Update();
			break;
		case "AnotherAction":
			//do other stuff
			break;
	}
}

Pretty cool, but what if you have 20-30 different actions? More...

Upgrading SharePoint feature in Visual Studio with CKS Dev extensions

Hi all! This is my revisited post from this one. I am going to show how we can call and test feature upgrade methods directly in visual studio. Lets start.

We need visual studio and CKS Dev extensions. CKS Dev adds additional deployment steps into your sharepoint project. Among them Upgrade Solution. This command simply run Update-SPSolutioncmdlet(or may be stsadm analog). To upgrade feature we need to call Upgrade explicit on the feature. CKS Dev hasn’t step “Upgrade feature”, that’s why we will use “Run PowerShell Script” step to upgrade particular feature. We start from creating custom deployment configuration.

Make this deployment configuration active. Create new folder under solution, for example “Scripts” and add new .ps1 file that will contain upgrade logic. As you remember, the first command in our deployment configuration is Upgrade Solution. It is significant, that this operation is asynchronous, it takes some time to complete, so we can’t upgrade particular feature while .wsp file, that contains this feature is still updating in central admin. We need to wait, until update solution operation will be completed, then we can call feature upgrade method. More...

How to disable drag-and-drop events in calendar.

Hi all! Based on this sharepoint.stackexchange question.

May be in some reasons you want to disable all drag-and-drop event for your calendar list. I don’t know if it possible through C# code, but it’s possible through javascript. In SP.UI.ApplicationPages.Calendar.js there is a factory method SP.UI.ApplicationPages.CalendarContainerFactory.create.This method creates and initializes instance of calendar using javascript. Among other parameters this function accepts context object that contains initialization info about calendar (cctx object). This object contains property DataSources (Array) and each array element is an object that has property named disableDrag. disableDrag false by default. The main idea is to substitute factory method and pass updated cctx object, that has disableDrag=true for every datasource. Edit page with calendar and add content editor web part. In content past this code:

<script type='text/javascript'> 
  ExecuteOrDelayUntilScriptLoaded(function(){
    var calendarCreate = SP.UI.ApplicationPages.CalendarContainerFactory.create;
        SP.UI.ApplicationPages.CalendarContainerFactory.create = function(elem, cctx, viewType, date, startupData) {
            if(cctx.dataSources && cctx.dataSources instanceof Array && cctx.dataSources.length > 0){
                for(var i = 0; i < cctx.dataSources.length; i++){
                    cctx.dataSources[i].disableDrag = true;
                }
            }
            calendarCreate(elem, cctx, viewType, date, startupData);
        }
  }, 'SP.UI.ApplicationPages.Calendar.js');
</script>   

or through code (don’t forget about proper disposing):

var site = new SPSite("http://localhost/sites/test/");
var web = site.OpenWeb();
var wpManager = web.GetLimitedWebPartManager("Lists/cal/calendar.aspx", PersonalizationScope.Shared);
var contentEditor = new ContentEditorWebPart();
var xmlDoc = new XmlDocument();
var xmlElement = xmlDoc.CreateElement("HtmlContent");
xmlElement.InnerText = @"<script type='text/javascript'> 
      ExecuteOrDelayUntilScriptLoaded(function(){
		var calendarCreate = SP.UI.ApplicationPages.CalendarContainerFactory.create;
        SP.UI.ApplicationPages.CalendarContainerFactory.create = function(elem, cctx, viewType, date, startupData) {
            if(cctx.dataSources && cctx.dataSources instanceof Array && cctx.dataSources.length > 0){
                for(var i = 0; i < cctx.dataSources.length; i++){
                    cctx.dataSources[i].disableDrag = true;
                }
            }
            calendarCreate(elem, cctx, viewType, date, startupData);
        }
  }, 'SP.UI.ApplicationPages.Calendar.js');
    </script>";
contentEditor.Content = xmlElement;
wpManager.AddWebPart(contentEditor, "Main", 0);

And that’s it. This code disables drag and drop for events for month, week, and day view. Hope this helps.

SharePoint 2010 Script On Demand–give me my scripts right now!

Hi all! May be you are already familiar with sharepoint 2010 script on demand feature. Recently I was playing with it and want to show some examples and explanations how it works.

There is a server control, that is responsible for rendering scripts on demand - ScriptLink .This control has 4 significant properties: LoadAfterUI, Name, OnDemand and Localizable.

  • LoadAfterUI (if true) means that your script link (or script) will be rendered at the vary end of the <form> tag (when all other html elements already loaded). if this property equals to false, script will be inserted right after <form> tag. Internally, methods RegisterStartupScript and RegisterClientScriptBlock used. The only difference between these two methods is where each one emits the script block. RegisterClientScriptBlock() emits the script block at the beginning of the Web Form (right after the <form runat="server"> tag), while RegisterStartupScript() emits the script block at the end of the Web Form (right before the </form> tag).
  • Name - name of script file (or path to that file – read below). This property uses by javascript as key that uniquely identify loaded script.
  • Localizable – if true, sharepoint try to find your script under “_layouts/1033/”
  • OnDemand – the most interesting property, indicates if we need this script load immediately, or if it should be downloaded on demand

Ok, some examples. Imagine we have script file myscript.js directly inside the layouts folder and we want to load it (OnDemand = false) . Its easy:

<SharePoint:ScriptLink runat="server" ID="sl" Localizable="False" LoadAfterUI="False" Name="myscript" OnDemand="False"></SharePoint:ScriptLink>

This action produces this output:

<script src="/_layouts/myscript.js?rev=7KqI9%2FoL9hClomz1RdzTqg%3D%3D" type="text/javascript"></script>

More...

Working with SPFielduserValue in item event receivers - some pitfalls.

Recently I posted about accessing lookup fields in item event receivers and about some pitfalls when you are using it.

Next part is about using PeopleEditor (or people picker as it sometimes called). Let's add new field to our list and see what will happen in event receivers.

First, ItemAdding:

In AfterProperties you can see "7". "7"?! Why? Because SPFieldUser that we was added also an a lookup field. Lookup list for this field is a hidden UserInformationList that trackes a part of user-related information, such as login name, display name, email, and some other. "7" is id of user in UserInformationList. You can get SPUser object by using method web.SiteUsers.GetByID(id), or you can use SPFieldUserValue to get user.

In ItemAdded you can see that our lookup has a value - this a login name of a user:

But sometimes you may encounter with problem, when user may not in UserInformationList. I delete user from this list using this small PS script:

More...

Accessing SharePoint lookup fields values in item receivers - some pitfalls.

Hi!

Recently I was playing with synchronous item event receivers and lookup fields and found some interesting behavior in different situations. I'll try to describe some pitfalls that I faced when develop item receivers for SharePoint.

So, lookup fields. When you try access to a lookup field in such events as Adding or Updating you may to have lookup value. But AfterProperties always contain only lookup Id, if you want to get lookup value you must query item by id. Imagine you have a list named "Software", it has title field and category lookup field (now we have 19 category types in "Category" list). When we try to add new item in "Software" list in ItemAdding event we can see:

Where "18" is an Id of category. And ItemAdded:

So, when use class SPFieldLookupValue, in ItemAdding event LookupValue equal to null (in AfterProperties) and not null in ItemAdded(in ListItem).

Let's try to update this item:

Situation is very similar - in AfterProperties we have an item Id (LookupId in SPFieldLookupValue class, LookupValue is null), and value in ListItem. In ItemUpdated event as you may know we will have both lookupId and LookupValue. Be aware of this SharePoint behavior.

More...