This is the second post in my mini series on how to extend the SharePoint 2010 Ribbon. First post can be found here.

The goal with this excersice is to extend the Editing Tools Insert tab with a smaller Insert Web Part drop-down, so we don’t have to expand the whole Web Part Gallery to insert a Web Part.

In the last post we created a Visual Studio 2010 solution and added the drop-down to the correct tab in the Ribbon using the CustomAction element and some new SharePoint 2010 XML syntax.

Quick Add Web Part

Readers with good memory/eyes see that I made some more enhancements to the drop-down…

Step 3: Create the JavaScript Page Component for the Ribbon control

To make our new drop-down to be contextual, load the correct content and to react to clicks and actions we need to create a JavaScript Page Component object. This is not currently documented in any way that I have found on MSDN, so this might not be the correct way to do it once we get to RTM. But it works!

First of all we need to add a JavaScript file to our solution, this JavaScript file should be deployed in the _LAYOUTS folder. Right click the project and select Add->SharePoint “Layouts” mapped folder. Then add a JavaScript file to that folder so that the project looks like this:

JavaScript file added.

I recommend that you use a naming standard as I’ve done, have your file end i UI.js, since this is how the UI JavaScript files are named in SharePoint 2010. It doesn’t really matter but it’s easier for other developers to understand your code then.

Now it’s time for some heavy weight JavaScript hacking. Add the following code to your JavaScript file:

   1:  Type.registerNamespace('QuickAddWebPart.UI');
   2:  QuickAddWebPart.UI.QuickAddWebPartPageComponent = function () {
   3:      QuickAddWebPart.UI.QuickAddWebPartPageComponent.initializeBase(this);
   4:  }
   5:  QuickAddWebPart.UI.QuickAddWebPartPageComponent.initialize = function () {
   6:      var ribbonPageManager = SP.Ribbon.PageManager.get_instance();
   7:      if (null !== ribbonPageManager) {
   8:          ribbonPageManager.addPageComponent(this.instance);
   9:          ribbonPageManager.get_focusManager().requestFocusForComponent(this.instance);
  10:      }
  11:  }
  12:  QuickAddWebPart.UI.QuickAddWebPartPageComponent.refreshRibbonStatus = function () {
  13:      SP.Ribbon.PageManager.get_instance().get_commandDispatcher().           executeCommand(Commands.CommandIds.ApplicationStateChanged, null);
  14:  }
  15:  QuickAddWebPart.UI.QuickAddWebPartPageComponent.prototype = {
  16:      init: function () {
  17:      },
  18:      getId: function () {
  19:          return 'QuickAddWebPartComponent';
  20:      },
  21:      getFocusedCommands: function () {
  22:          return [];
  23:      },
  24:      getGlobalCommands: function () {
  25:          return ['QuickAdd_Button', 'QuickAdd_Populate', 'QuickAdd_Query', 'QuickAdd_Add'];
  26:      },
  27:      isFocusable: function () {
  28:          return true;
  29:      },
  30:      receiveFocus: function () {
  31:          return true;
  32:      },
  33:      yieldFocus: function () {
  34:          return true;
  35:      },
  36:      canHandleCommand: function (commandId) {      
  37:          return true;
  38:      },
  39:      handleCommand: function (commandId, properties, sequence) {
  40:           return true;
  41:      }
  42:  }
  43:  QuickAddWebPart.UI.QuickAddWebPartPageComponent.         registerClass('QuickAddWebPart.UI.QuickAddWebPartPageComponent', CUI.Page.PageComponent);
  44:  QuickAddWebPart.UI.QuickAddWebPartPageComponent.instance =          new QuickAddWebPart.UI.QuickAddWebPartPageComponent();
  45:  QuickAddWebPart.UI.QuickAddWebPartPageComponent.initialize();

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

This piece of JavaScript creates a new JavaScript object called QuickAddWebPartPageComponent (line 2) and is registered in the QuickAddWebPart.UI namespace (line 43). The object has a set of methods that is used by the Ribbon to query the component for which actions it supports and the object also has methods such as handling the actions and focus of the control. This is exactly how the native SharePoint 2010 UI objects behave.

There are a few important things to notice here:

  1. getGlobalCommands (line 24) returns an array of all our commands that we defined in the custom action in the previous post (QueryCommand, Command etc)
  2. There will be a lot of functionality added to canHandleCommand (line 36) and handleCommand (line 39) and other methods in the upcoming posts
  3. To create your own just replace QuickAddWebPart with your own string.

If we deploy this just as it is now, we won’t load the JavaScript file so we have to create a load control for this.

Step 4: Load the JavaScript

The easiest way to load our JavaScript is to create a delegate control and add that control to AdditionalPageHead.

First of all I add some more XML to the elements.xml file, just after our CustomAction:

Delegate Control…

This XML tells SharePoint to load the control and place it in the AdditionalPageHead. Note how I’m using the new Visual Studio 2010 tokens to replace the namespace and assembly name so I don’t have to write them and figure out the strong name. My control is called ScriptLoader and that control is added to the project as a new Class.

To load the control, see the code below, I use the ScriptLink.RegisterScriptAfterUI method, which is a part of the Microsoft.SharePoint.dll. I also make sure that I add some other necessary JavaScripts, that the page component and my code is dependant on.

   1:  namespace Wictor.QuickAddWebPart {    
   2:      public class ScriptLoader : WebControl {
   3:          protected override void OnPreRender(EventArgs e) {
   4:              SPRibbon currentRibbon = SPRibbon.GetCurrent(this.Page);    
   5:              if (currentRibbon != null && currentRibbon.IsTabAvailable("Ribbon.EditingTools.CPInsert")) {
   6:                  ScriptLink.RegisterScriptAfterUI(this.Page, "SP.Core.js", false, true);
   7:                  ScriptLink.RegisterScriptAfterUI(this.Page, "CUI.js", false, true);
   8:                  ScriptLink.RegisterScriptAfterUI(this.Page, "core.js", true, false);
   9:                  ScriptLink.RegisterScriptAfterUI(this.Page, "SP.Ribbon.js", false, true);
  10:                  ScriptLink.RegisterScriptAfterUI(this.Page, "SP.Runtime.js", false, true);
  11:                  ScriptLink.RegisterScriptAfterUI(this.Page, "SP.js", false, true);
  12:                  ScriptLink.RegisterScriptAfterUI(this.Page, "Wictor.QuickAddWebPart/QuickAddWebPart.ui.js", false, true);
  13:              }
  14:              base.OnPreRender(e);
  15:          }
  16:      }
  17:  }

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

To avoid that the scripts are loaded unnecessary I get the current Ribbon instance (line 4) and checks if the page has a Ribbon and if the Editing Tools->Insert tab is available (line 5). If you compile your project now it will fail, since the IsTabAvailable method is defined in the Ribbon class (not the SPRibbon class) which exists in the Web.Command.UI.dll assembly, so we need to add a reference to that DLL.


We also need to add this control to the Safe Controls. This is done by looking at the properties of the item that contains the elements.xml and selecting Safe Control Entries and then add our control to this collection.


Fill in as below, note that I’m using the replaceable tokens here also.

Safe Control entry

Now we can build and deploy our solution. It still looks the same, there are no items in the drop-down yet. Until next part you can fiddle with the different methods in the Page Component and insert some JavaScript alerts to see when the methods are invoked (that’s how I figured out how it works…)

Until next time.