Display Template Deployment in SharePoint 2013


Hi Guys,

New way to transform search result introduces in SharePoint 2013 which provide a good user experience through the use of display templates. It is far better then using XSLT in SharePoint 2010 to use to customize that display. It is really frustrating while understanding XSLT display templates. The great thing about display templates is that you create them by leveraging skills that many developers already possess: HTML and JavaScript.

The most likely approach to creating display templates is to start with an existing display template HTML file and customize it. It’s not too difficult when you get the hang of the _#= (underscore pound equals) syntax. It’s very important to understand what happens when you edit that HTML file. When you click save SharePoint creates a JavaScript file and associates the two together. (The same thing happens when creating master pages using the design manager but HTML to MASTER file). When you select your display template in the content by search web part it is actually looking for the JavaScript file not the HTML file.

The Dilemma

Putting HTML design files in the SharePoint Master Page Gallery is like playing with the mysterious black box, we never predict what is going to happen with them.

This blog post covers my experiences with provisioning Display Templates to the Master Page Gallery in SharePoint 2013. In order to get more control on the Branding package you should add these design files to your visual studio project. Here are the few very important points about the module attributes which might be used to deploy the files to gallery:

  1. Never Set the Level Attribute of the Display Template to Published:
    When you do this, and you only provision the HTML file, the JavaScript file doesn’t gets generated. The JavaScript version only generates for Draft versions of an HTML file.
  2. Make Use of the ReplaceContent=”True” Attribute:
    In order to update the HTML file or JavaScript file you need to make use of the ReplaceContent attribute. The file content of your  doesn’t get updated if you didn’t mention this attribute.
  3. You don’t need to Specify Additional Metadata/Properties:
    These properties should all be in the Display Template Head section. Example of the Display Template header section:
    <mso:CustomDocumentProperties>
    <mso:CompatibleManagedProperties msdt:dt=”string”></mso:CompatibleManagedProperties>
    <mso:TemplateHidden msdt:dt=”string”>0</mso:TemplateHidden>
    <mso:MasterPageDescription msdt:dt=”string”></mso:MasterPageDescription>
    <mso:ContentTypeId msdt:dt=”string”>0x0101002039C03B61C64EC4A04F5361F385106601 </mso:ContentTypeId>
    <mso:TargetControlType msdt:dt=”string”>;#Refinement;#</mso:TargetControlType>
    <mso:HtmlDesignAssociated msdt:dt=”string”>1</mso:HtmlDesignAssociated>
    <mso:HtmlDesignConversionSucceeded msdt:dt=”string”>True</mso:HtmlDesignConversionSucceeded>
    <mso:HtmlDesignStatusAndPreview msdt:dt=”string”>Link to the file, Conversion successful.</mso:HtmlDesignStatusAndPreview>
    </mso:CustomDocumentProperties>
  4. Provision the HTML and the JavaScript Files Together:
    When you try to provision only the HTML file, the first time everything will run smoothly. Your JavaScript file will be created, and metadata is correctly filled in. But from the moment you make any modification to the HTML file in your solution and provision the file again, the HTML file gets updated, but the JavaScript file isn’t.The best way that worked for me is to provision the HTML and the JavaScript file together. It seems that the Design Manager also works this way. For the moment a file gets updates, it will package the HTML and JavaScript file.The way I’m doing this right now is like this:<Module Name=”_catalogs” Url=”_catalogs/masterpage/Display Templates/Content Web Parts” RootWebOnly=”TRUE”>  <File Url=”Control_Custom_Refinement.html” Type=”GhostableInLibrary” Level=”Draft” ReplaceContent=”true”></File>  <File Url=”Control_Custom_Refinement.js” Type=”GhostableInLibrary” Level=”Draft” ReplaceContent=”true”>    <Property Name=”ContentType” Value=”Display Template Code” />  </File></Module>
  5. Create a Feature Receiver to Update and Publish your Display Templates:
    When the display templates are provisioned, you will need to do the following two things:Trigger an update > this is needed to update the JavaScript file (so the JavaScript file should definitely have the correctly converted markup);
    The update can be triggered with “item.Update()”;
    Publish the file > otherwise they will not be available of site readers.The best way to update and publish your display templates is via a Feature Receiver on the FeatureActivated event. This is what I also used to do in SharePoint 2010 to publish the master page and page layouts when using a Sandboxed Solution.You only need to publish the HTML version, from the moment the HTML file gets published, the engine will automatically published the associated JavaScript file.

On activation, the feature provisions the files, and Master Page Gallery receiver code performs the conversions, but the files are still drafts.For guaranteed usability, the HTML files should be published. This can be done manually, but it can also be dealt with in a feature event receiver. The basis for this is that the HTML file be stamped to the feature by issueing it the Feature ID as a property in Elements.xml:

private string[] folderUrls = { “_catalogs/masterpage/Display Templates/Content Web Parts” };

 
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            SPSite site = properties.Feature.Parent as SPSite;
            if (site != null)
            {
                SPWeb rootWeb = site.RootWeb;
 
                SPList gallery = site.GetCatalog(SPListTemplateType.MasterPageCatalog);
 
                if (gallery != null)
                {
                    SPListItemCollection folders = gallery.Folders;
                    string featureId = properties.Feature.Definition.Id.ToString();
 
                    foreach (string folderUrl in folderUrls)
                    {
                        SPFolder folder = GetFolderByUrl(folders, folderUrl);
                        if (folder != null)
                        {
                            PublishFiles(folder, featureId);
                        }
                    }
                }
            }
        }
        private static SPFolder GetFolderByUrl(SPListItemCollection folders, string folderUrl)
        {
            if (folders == null)
            {
                throw new ArgumentNullException(“folders”);
            }
 
            if (String.IsNullOrEmpty(folderUrl))
            {
                throw new ArgumentNullException(“folderUrl”);
            }
 
            SPFolder folder = null;
 
            SPListItem item = (from SPListItem i
                               in folders
                               where i.Url.Equals(folderUrl, StringComparison.InvariantCultureIgnoreCase)
                               select i).FirstOrDefault();
 
            if (item != null)
            {
                folder = item.Folder;
            }
 
            return folder;
        }
        private static void PublishFiles(SPFolder folder, string featureId)
        {
            if (folder == null)
            {
                throw new ArgumentNullException(“folder”);
            }
 
            if (String.IsNullOrEmpty(featureId))
            {
                throw new ArgumentNullException(“featureId”);
            }
 
            SPFileCollection files = folder.Files;
            var drafts = from SPFile f
                                  in files
                                  where String.Equals(f.Properties[“FeatureId”] as string, featureId, StringComparison.InvariantCultureIgnoreCase) &&
                                  f.Level == SPFileLevel.Draft
                                  select f;
 
            foreach (SPFile f in drafts)
            {
                f.Publish(“”);
                f.Update();
            }
        }
Hope that helps you.
Happy SharePointing 🙂
Advertisements

Custom Site action using MenuItemTemplate


Hi,

Site action links are by default added by sharepoint but there could be some cases when you feel like adding new site action to navigate to your custom page or OOB page. In this blog, I will explain how you can and what are the various way to do that.

Solution 1 (Using Custom Action):

You must heard this term if ever got chance to customize the ribbon or any contextual menu. You can very easily add this element to your custom farm solution just by adding a empty module and then add following code in to it.
<?xml version=”1.0″ encoding=”utf-8″?>
<Elements xmlns=”http://schemas.microsoft.com/sharepoint/”&gt;

<CustomAction Id=”CustomScript”
ScriptBlock=”function OpenDialog() {
window.scrollTo(0, 0);
var context = SP.ClientContext.get_current();
var siteUrl = context.get_url();
if (siteUrl == ‘/’) siteUrl = ”;
var options = SP.UI.$create_DialogOptions();
options.url = siteUrl + ‘/_layouts/<url of your custom page>’;
options.autosize= true;
SP.UI.ModalDialog.showModalDialog(options);
}”
Location=”ScriptLink”>
</CustomAction>

<CustomAction Id=”MyCustomAction”GroupId=”SiteActions”
Location=”Microsoft.SharePoint.StandardMenu”
Sequence=”100″
Title=”Add News”
Description=”Link to Add new news for Sg finance” >
<UrlAction Url=”javascript:OpenDialog();”/>
</CustomAction>
</Elements>

Solution 2 (Using MenuItemTemplate):

If you ever notice the master page of your site(Oslo.master or Seattle.master), there is a “SiteActions” tag present which contains the definition of default site action links. Now depending upon the customer/project customization potential we can add our custom link to the master page. What I mean is if you are free to customize or create custom master page this approach will be best for you.

Open the master page in any tool of your choice, now find out the site actions tag and notice the various MenuItemTemplate tags for each link. Read more about them here.

Now copy and paste one of the tag to customize it. Now change the title and descriptions or may be the permission if you want. Notice the “ClientOnClickScriptContainingPrefixedUrl” attribute there which can contains the action to be performed when link will be clicked. Read more about it here.

For an example, In case you want to open the pop up then like “Add page” then use the OpenCreateWebPageDialog(‘~siteLayouts/createwebpage.aspx’) code.

If your link will navigate to new page then use GoToPage  like: GoToPage(‘~siteLayouts/settings.aspx’). Whole code should looks like:

<SharePoint:MenuItemTemplate runat=”server” ID=”MenuItem_CreateNews”
Text=”<%$Resources:XXX,SiteAction_AddNews_Title;%>”
Description=”<%$Resources:XXX,SiteAction_AddNews_Desc%>”
MenuGroupId=”200″
Sequence=”230″
UseShortId=”true”
ClientOnClickScriptContainingPrefixedUrl=”OpenCreateWebPageDialog(‘~siteCollectionLayouts/CreatePublishingPageDialog.aspx’)”
PermissionsString=”ManageLists, ManageSubwebs”
PermissionMode=”Any” />

You can use various tokens to create proper url to navigate: Tokens in Sharepoint.

Hope this helps you to create custom site setting link.

Happy SharePointing 🙂