Tag Archives: SharePoint Designer

Google Maps Display Template – SharePoint 2013 – Part 1

As the most of you will know by now is that SharePoint 2013 has a new web part called the “Content Search” web part. This web part display’s search result by using specific display templates.

For one of our clients we were asked to display location/office information on a Google Maps card based on information they save in a list.  We first had the idea of using the new Geo Location fields that are pretty awesome. But we had a hard requirement for using Google Maps because they already had a licence for using that.

If you want more information about the Geo Location field you can read about here:

The easiest way to display this information is retrieving the results by its content type with the Content Search web part and using a Google Maps Display Template to display those results.

There are two primary types of display templates:

  • Control templates determine the overall structure of how the results are presented. Includes lists, lists with paging, and slide shows.

  • Item templates determine how each result in the set is displayed. Includes images, text, video, and other items.

The control display template defines the HTML structure for the overall layout and the item template defines the HTML structure for the item.

Combined HTML output of a control display template and item display template

If you want to read more information about display templates here is a good article:

SharePoint 2013 Design Manager display templates

In this Part we will be creating the item template. The easiest way to create a new item display template is using SharePoint Designer and create a copy of another display template.

The display templates can be found here:

All Files – _catalogs – masterpage – Display Templates – Content Web Parts

To get a new item display template you will need to copy an existing item template, for this example we will create a copy of the “Item_TwoLines.html” and rename it to “Item_GoogleMarker.html”.

When you open the file in edit mode you will see that there is a Title attribute on the top of the page. Change this title to Google Maps Marker because the item we will retrieve will represent markers on the map.

The result we will be retrieving will have the following information:

  • Title
  • Longitude
  • Latitude
  • Description
  • Address
  • Site Url (Url to a SharePoint site)

In order to get this information from search you will have to create managed properties for the specific field. In this post I will not tell you how to create those for more information you can read this post or look on MSDN for more information:

If you look further in the display template you will see the property “ManagedPropertyMapping” this will map the properties to specific variables in the file. To which property they are mapped can be changed in the tool part of the web part

image

<mso:ManagedPropertyMapping msdt:dt="string">&#39;Link URL&#39;{Link URL}:&#39;Path&#39;,&#39;Line 1&#39;{Line 1}:&#39;Title&#39;,&#39;Line 2&#39;{Line 2}:&#39;&#39;,&#39;FileExtension&#39;,&#39;SecondaryFileExtension&#39;</mso:ManagedPropertyMapping>

Each property mapping exists out of three variables separated by &#39;,&#39; and the complete properties are separated by ‘, ‘.

For example “&#39;Line 1&#39;{Line 1}:&#39;Title&#39;”:

  • The first “Line 1” will represents the value in the display template.
  • The second “{Line 1}” represents the description and is displayed in the tool part. You can change this to each value you want.
  • The third “Title” is the default managed property it is mapped to.

For our item template we will extend the property with our own values we need to be able to retrieve the right values from the search engine.

<mso:ManagedPropertyMapping msdt:dt="string">&#39;Link URL&#39;{Link URL}:&#39;Path&#39;,&#39;Line 1&#39;{Title}:&#39;Title&#39;,&#39;Line 2&#39;{Latitude}:&#39;Title&#39;,&#39;Line 3&#39;{Longtitude}:&#39;Title&#39;,&#39;Line 4&#39;{Description}:&#39;Title&#39;,&#39;Line 5&#39;{Address}:&#39;Title&#39;,&#39;Line 6&#39;{Site Url}:&#39;Title&#39;</mso:ManagedPropertyMapping>

When this is done you can change the “MasterPageDescription” property to the value of your choice.

When you go further down into the display template the values are retrieved within the div called “TwoLines”.

<!--#_
var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_2lines_");

var linkURL = $getItemValue(ctx, "Link URL");
linkURL.overrideValueRenderer($urlHtmlEncode);
var iconURL = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);

var line1 = $getItemValue(ctx, "Line 1");
var line2 = $getItemValue(ctx, "Line 2");
line1.overrideValueRenderer($contentLineText);
line2.overrideValueRenderer($contentLineText);

var containerId = encodedId + "container";
var pictureLinkId = encodedId + "pictureLink";
var pictureId = encodedId + "picture";
var dataContainerId = encodedId + "dataContainer";
var line1LinkId = encodedId + "line1Link";
var line1Id = encodedId + "line1";
var line2Id = encodedId + "line2";
_#-->

Replace this by the following code in which we get all of the values from our properties and use basically the same code the was in the original template:

<!--#_
  var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_2lines_");
  var linkURL = $getItemValue(ctx, "Link URL");
  linkURL.overrideValueRenderer($urlHtmlEncode);
  var iconURL = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);
       
  var title = $getItemValue(ctx, "Line 1");
  var latitude = $getItemValue(ctx, "Line 2");
  var longtitude = $getItemValue(ctx, "Line 3");
  var description = $getItemValue(ctx, "Line 4");
  var address = $getItemValue(ctx, "Line 5");
  var siteUrl = $getItemValue(ctx, "Line 6");
  title.overrideValueRenderer($contentLineText);
  latitude.overrideValueRenderer($contentLineText);
  longtitude.overrideValueRenderer($contentLineText);
  siteUrl.overrideValueRenderer($contentLineText);
      
  var itemId = ctx.CurrentItemIdx;
_#-->

Now that we have all of the values for a item. It is time to write the HTML we want for the display template. The easiest way is to place all of the information about the marker in a hidden input field. In the control template we will then retrieve the information and display it on the map.

The complete display template will then look like this:

<html xmlns:mso="urn:schemas-microsoft-com:office:office" xmlns:msdt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"> 
<head>
<title>Google Map Marker</title>

<!--[if gte mso 9]><xml>
<mso:CustomDocumentProperties>
<mso:TemplateHidden msdt:dt="string">0</mso:TemplateHidden>
<mso:ManagedPropertyMapping msdt:dt="string">&#39;Link URL&#39;{Link URL}:&#39;Path&#39;,&#39;Line 1&#39;{Title}:&#39;Title&#39;,&#39;Line 2&#39;{Latitude}:&#39;Title&#39;,&#39;Line 3&#39;{Longtitude}:&#39;Title&#39;,&#39;Line 4&#39;{Description}:&#39;Title&#39;,&#39;Line 5&#39;{Address}:&#39;Title&#39;,&#39;Line 6&#39;{Site Url}:&#39;Title&#39;</mso:ManagedPropertyMapping>
<mso:MasterPageDescription msdt:dt="string">This Item Display Template will show a marker when used with the the Google Maps control.</mso:MasterPageDescription>
<mso:ContentTypeId msdt:dt="string">0x0101002039C03B61C64EC4A04F5361F385106603</mso:ContentTypeId>
<mso:TargetControlType msdt:dt="string">;#Content Web Parts;#</mso:TargetControlType>
<mso:HtmlDesignAssociated msdt:dt="string">1</mso:HtmlDesignAssociated>
<mso:HtmlDesignConversionSucceeded msdt:dt="string">True</mso:HtmlDesignConversionSucceeded>
<mso:HtmlDesignStatusAndPreview msdt:dt="string"></mso:HtmlDesignStatusAndPreview>
</mso:CustomDocumentProperties>
</xml><![endif]-->
</head>

<body>
    <script>
        $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
    </script>

    <div id="TwoLines">
        <!--#_
        var encodedId = $htmlEncode(ctx.ClientControl.get_nextUniqueId() + "_2lines_");
        var linkURL = $getItemValue(ctx, "Link URL");
        linkURL.overrideValueRenderer($urlHtmlEncode);
        var iconURL = Srch.ContentBySearch.getIconSourceFromItem(ctx.CurrentItem);
        
        var title = $getItemValue(ctx, "Line 1");
        var latitude = $getItemValue(ctx, "Line 2");
        var longtitude = $getItemValue(ctx, "Line 3");
        var description = $getItemValue(ctx, "Line 4");
        var address = $getItemValue(ctx, "Line 5");
        var siteUrl = $getItemValue(ctx, "Line 6");
        title.overrideValueRenderer($contentLineText);
        latitude.overrideValueRenderer($contentLineText);
        longtitude.overrideValueRenderer($contentLineText);
        siteUrl.overrideValueRenderer($contentLineText);
        
        var itemId = ctx.CurrentItemIdx;
        _#-->
        <input type="hidden" id="_#= itemId =#_-Location" value="_#= title =#_;_#= latitude =#_;_#= longtitude =#_;_#= description =#_;_#= address =#_;_#= siteUrl =#_">
    </div>
</body>
</html>

One thing to notice is that we give the hidden input the ID of the result “var itemId = ctx.CurrentItemIdx;” so that we are able to retrieve all of the items in the control template by a specific ID.

In part 2 of the series I will show you how you can finish the set by creating a control template that will result in to the following:

Google Maps Card

Creating a SharePoint Designer Action for the Sandbox

One of the new features in SharePoint 2010 was the possibility to create Sandbox solutions. Sandbox solutions are custom build solutions that run in another process with another CAS policy.

Sandbox solutions allow you to do the following:

  • Deploy custom code to you site collection when you do not have access to Central Administration.
  • Sandbox solutions cannot jeopardize the stability of your farm.
  • With SharePoint in a hosted environment you will be able to deploy Sandboxed solutions.

With the ability to deploy Sandbox solutions you also have some important restrictions:

  • A certain part off the SharePoint API is not available.
  • You cannot read/write to the file system.
  • You cannot call assemblies deployed out of Global Assembly Cache.

After all Sandbox solutions are a powerful feature of SharePoint. SharePoint designer gives you the possibility to develop Custom actions. But when you try to develop those for the sandbox it is totally different.

Let’s start of by creating a empty SharePoint project. When you created a empty project add a new Class file. Mark the class public and add a method that returns a Hashtable that has a SPUserCodeWorkflowContext object as parameter. The Hashtable will give you the ability to return values in the workflow. The SPUserCodeWorkflowContext on the other hand is a ‘In’ parameter.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.SharePoint.UserCode;
using Microsoft.SharePoint;

namespace Motion10.SharePoint.Sandbox.Designer
{
    public class SPCreateSubSiteAction
    {
        public Hashtable CreateSubSite(SPUserCodeWorkflowContext context)
        {
        }
    }
}

In the above code example you see that I created a method called ‘CreateSubSite’ within this method you can add the logic of your custom action. In the upcoming examples we will create a action that creates a sub site.

To add the custom action to SharePoint you have to create a new elements file in which you have  to specify the custom action.

<WorkflowActions>
  <Action Name="Create Sub Site"
          SandboxedFunction="true"
          Assembly="$SharePoint.Project.AssemblyFullName$"
          ClassName="Motion10.SharePoint.Sandbox.Designer.SPCreateSubSiteAction"
          FunctionName="CreateSubSite"
          AppliesTo="all"
          Category="Motion10 Designer Actions">
  </Action>
</WorkflowActions>

To be able to add parameters to the method that you need to create a sub site we will have to define a ‘RuleDesigner’ section to enable users to fill in those parameters.

<RuleDesigner Sentence="Create sub site with the title: %1, url: %2 and description: %3.">
  <FieldBind Field="Title" Text="Title" Id="1" DesignerType="TextBox" />
  <FieldBind Field="Url" Text="Url" Id="2" DesignerType="TextBox" />
  <FieldBind Field="Description" Text="Description" Id="3" DesignerType="TextBox" />
</RuleDesigner>

The ‘RuleDesigner’ section has to be placed within the ‘Action’ section. In the ‘Action’ section you also have to place a ‘Parameters’ section to pass the actual values in the workflow action.

<Parameters>
  <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" Direction="In" DesignerType="Hide" />
  <Parameter Name="Title" Type="System.String, mscorlib" Direction="In" DesignerType="ParameterNames" />
  <Parameter Name="Url" Type="System.String, mscorlib" Direction="In" DesignerType="ParameterNames" />
  <Parameter Name="Description" Type="System.String, mscorlib" Direction="In" DesignerType="ParameterNames" />
</Parameters>

With all of this in place we can extend our method with the correct parameters and create a simple action to create a sub site.

public Hashtable CreateSubSite(SPUserCodeWorkflowContext context, string Title, string Url, string Description)
{
    //hashtable that will be returned can be used for return values.
    Hashtable retVal = new Hashtable();

    using (SPSite site = new SPSite(context.CurrentWebUrl))
    {
        using (SPWeb web = site.OpenWeb())
        {
            try
            {
                using (SPWeb newWeb = web.Webs.Add(Url, Title, Title, 1033, web.WebTemplate, false, false))
                {
                    SPWorkflow.CreateHistoryEvent(web, context.WorkflowInstanceId, 0, web.CurrentUser, TimeSpan.Zero, "Information", "Sub site created from a Sandbox activity", string.Empty);
                }
            }
            catch (Exception ex)
            {
                SPWorkflow.CreateHistoryEvent(web, context.WorkflowInstanceId, 0, web.CurrentUser, TimeSpan.Zero, "Error", ex.Message,string.Empty );
            }
        }
    }
    return retVal;
}

Make sure you add the elements file to feature that is scoped to ‘Site’ and deploy the Sandbox solution. Open SharePoint Designer and you will see that you have the action available!