Add custom commands on Infopath browser form ribbon

In Infopath 2010 browser form, the commands are shown on Ribbon, so from usability point of view, it would be great if we have our custom commands reside in the Ribbon.  The OOB Ribbon are provisioned by a SharePoint  feature called IPFSSiteFeatures, one of the xml files in it contains the Ribbon definition, IPFSRibbon.xml. And the command handlers are defined in javascript file, Core.js, in <hive 14>\TEMPLATE|LAYOUTS\INC

Infopath Custom Command

In the picture, we can see I have added a custom command called Complete. The  command will display a javascript prompt and then perform a postback where the code behind run a server operation. In my case it is set the field on the form, extract some data in the form into custom lists for reporting and send emails to interested party.

Below is the ribbon definition for the Complete command. The most important part is the Location, I put my custom command into the first Ribbon group (Ribbon.ContextualTabs.InfoPathHomeTab.FormAction). The command handler is a javascript function defined in CommandUIHandlers. And also make sure to provision this custom action as site feature (Scope=Web) as this custom command will be added to any Form libraries in the site.

<CustomAction Id="IFCustomRibbon" Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions>
         <CommandUIDefinition Location="Ribbon.Tabs.InfoPathHomeTab.FormActions.Controls._children">
             <Button Id="Ribbon.Tabs.Lcms.FormActions.Controls.Complete"
               Sequence="70" Command="CompleteForm"
               Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png" Image16by16Top="-48" Image16by16Left="-48"
              Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="0" Image32by32Left="-96"
              LabelText="Complete"
              TemplateAlias="o2"
              ToolTipTitle="Complete"
              ToolTipDescription="$Resources:CcaLcms,cui_desc_CompleteForm;"/>
        </CommandUIDefinition>
      </CommandUIDefinitions>
   <CommandUIHandlers>
       <CommandUIHandler Command="CompleteForm" CommandAction="javascript:CompleteForm();
          function CompleteForm(){
             if(confirm('This will complete the form and send notification to interested party'))
             {
               var $command = $get('FormControl_V1_I1_B29');
               $command.click();
             }
          }
        "/>
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>

The Command handler is mapped to a javascript function. In it it will display a confirmation to users and then perform a postback. The trick to do a postback is on the Infopath form we have a hidden button that runs custom code during on click event. As it is hidden the button wouldn’t be displayed on the browser form but its html representation (<input>) can be still be found in form’s html.

To have the button callable in javascript we need to get the button Id. This can be achieved by using IE Developer Tool or Firebug to inspect the browser form and get the id of the html input tag that represents the button. In this example The html input tag would have attributes: buttonid=FormComplete and value=Complete. The
FormControl_V1_I1_B29 in the javascript above is the input tag id of the Complete button.

With the mechanism we basically can execute any Infopath buttons from our ribbon’s custom commands, such as run a workflow, open a modal dialog, etc. Though there is a catch that the buttons id tend to change if we change the structure of the form, but if we put the hidden buttons on the very top of the form, we can avoid the changes of the ids when the form structure changes.

Additionally we also can call the submit and close from javascript. I got this following functions from Core.js mentioned at the beginning of the article. You can dig the Core.js to find more functions.

   var a = IPFSRibbon_GetFocusedFormControlId();
   IPFSRibbon_HandleButtonClick(a, 'submit');  //this will submit the form
   IPFSRibbon_HandleButtonClick(a, 'close');   //this will close the form
   var navigateUrl = CurrentFormData_UrlToNavigateToOnClose(a);

NOTE. You must delete the browser’s cache files every time deploying the changes of the ribbon definition (CustomAction).

Microsoft SharePoint 2010, Infopath 2010, .NET

Ribbon: insert any Web Part using javascript

In this article I will show how to add a web part using SharePoint 2010′s javascript. As we know we can add web parts on a page using command in Contextual Ribbon Tab called Insert Web Part. Behind the scene there is a server control called WebPartAdder, this control registers a javascript file called wpadder.js containing functions for selecting  web part from web part gallery and inserting it. Tapping into these functions we can add any web parts purely using javascript.

As an example I will add a custom control in Insert Web Part Contextual Ribbon as shown below. The control would insert Contet Editor WebPart into a web part zone on a page.

Here is the ribbon definition for the Insert Content Editor command.

<CustomAction Id="AddCustomWebPart"
                    RegistrationId="100" RegistrationType="List"
                    Location="CommandUI.Ribbon">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition Location="Ribbon.WebPartInsert.WebParts.Controls._children">
          <Button
            Id="Ribbon.DL.WebPartInsert.WebParts.WebPart"
            Sequence="40"
            Command="insertMyWebPart"
            LabelText="Insert Content Editor"
            Image16by16="/_layouts/images/edit.gif"
            Image32by32="/_layouts/images/placeholder32x32.png"
            TemplateAlias="o1"
            ToolTipTitle="Insert my web part"
            ToolTipDescription="$Resources:core,cui_STT_ButInsertWebPart;"/>
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler Command="insertMyWebPart" CommandAction="javascript: addMyWebPart('Media and Content','Content Editor');"/>
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>

In this example our CustomAction is applicable for general/custom list (RegistrationType=List and RegistrationId=100) . This msdn article lists all OOB ListTemplates Id. The location of the custom command is in  Ribbon.WebPartInsert.WebParts.Controls (Contextual Tab Insert Web Part Group). The command handler for the web part is our javascript function call addMyWebPart. Below is the the implementation of addMyWebPart.
function addMyWebPart(wpCategory, wpTitle) {
   var webPartAdder = SP.Ribbon.WebPartComponent.getWebPartAdder();
   var webPart = findWebPart(webPartAdder, wpCategory, wpTitle);
   if (webPart) {
     var selectedZone = $get('_wzSelected').value;
     if (!selectedZone) selectedZone = "Main";
       webPartAdder.addItemToPageByItemIdAndZoneId(webPart.id, selectedZone);                           
   }
   else
       alert('web part not found!');
}

function findWebPart(webPartAdder, category, wpTitle){
  if(webPartAdder){
    var wpCategory = findByTitle(webPartAdder._cats, category); 
    if(wpCategory)
      return findByTitle(wpCategory.items, wpTitle);
  }
}

function findByTitle(list, title){
   for (i=0; i < list.length; i++){
     var item = list[i];
     if(item.title == title)
       return item;
   }
}

The function’s arguments are the  web part’s Category and web part’s Title of the web part defined in web part gallery (_catalogs/wp).  First thing it would try to get the WPAdder instance. WPAdder class are defined in wpadder.js. It has several properties and method such as :

  • addItemToPageByItemIdAndZoneId method: this would add the web part into a page given the web part item id and zone id
  • _cats: containing the list of web part categories
  • Each web part category has items properties containing the list of web parts in the category
  • Both category and item have title property

After getting the WPAdder instance it would try to find the web part by iterating the web part category list and matching the title of the category. If the category found it would iterate the items in the category and match the title of the item. Having found the item, it would try to get the selected web part zone by checking the hidden variable called _wzSelected. Then after that called the method to add the webpart to the page.

We can provision the javascript above using another CustomAction with Location attribute sets to ScriptLinks as shown below.

 <CustomAction Id="AddWpScript" ScriptSrc="RibbonTest/RibbonScript.js" Location="ScriptLink" Sequence="100"></CustomAction>

This picture shows the project structure in visual studio. Put the 2 CustomActions (ribbon definition and javascript def) into the elements.xml and the javascript into the RibbonScript.js. Off-course, it needs a feature that contains the WpAdderElement to provision it.

To see how it works, go to any custom list and click Modify Form Web Part from the ribbon or add query string DisplayMode=Design to any view for example to see the design mode of the default view we can do  AllItems.aspx?DisplayMode=Design. This would open the page on Design mode  and then we can insert the Content Editor Web Part using our custom command in the Insert Web part Contextual Tab.

With this mechanism we can add any web part to page purely using javascript.

Microsoft SharePoint 2010,SharePoint Designer, SharePoint Workflow, Web Part