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

SharePoint Color Palette Tool (ThemeSlots)

Many off you may have seen it in presentations of Microsoft. The tool was then called ThemeSlots. Today I stumbled on the release and it is now called “SharePoint Color Palette Tool”.

This tool helps you to create your own SPColor file for SharePoint 2013 by giving you a handy interface with a preview window.

SharePoint Color Palette Tool

 

You can download the tool here:

http://www.microsoft.com/en-us/download/details.aspx?id=38182

Active Directory Picture Synchronization

When you have stored the pictures of employees in Active Directory you would like to have the option to synchronize these pictures to their SharePoint profile.

This article describes the steps you need to take to import them into the SharePoint profiles.

 

1. Change the mapping of the Picture profile field.

Navigate to the User Profile Service Application and got to “Manage User Properties”. Find the picture property and select the edit menu item. Add a new Mapping to the “thumbnailPhoto” attribute and select “Ok” when you are done.

Before:

AD Mapping

After:

AD Mapping After

2. Perform a Full Import

On the User Profile Service Application select “Start Profile Synchronization” to start a Full Synchronization.

3. Run the command Update-SPProfilePhotoStore

This command let will create the profile pictures in the “User Photo” library in the Mysite host site collection. Run this command with the following options:

Update-SPProfilePhotoStore -MySiteHostLocation [Your Mysite Host Location] -CreateThumbnailsForImportedPhotos 1

 

4. Check the profiles for their pictures.

 

One downside to this is that you need to rerun the Update-SPProfilePhotoStore when you have a new Employee for example.

 

When you would like to try this out on your environment you can use the following PowerShell script for importing a picture in Active Directory.

#parameters
$username = "tpicture"
$picture = "C:\Pictures\msftplayground.png"

#get the active directory information
$dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$root = $dom.GetDirectoryEntry()
$search = [System.DirectoryServices.DirectorySearcher]$root
$search.Filter = "(&(objectclass=user)(objectcategory=person)(samAccountName=$username))"
$result = $search.FindOne()

#if the result not equal to null
if ($result -ne $null){
    $user = $result.GetDirectoryEntry()

    #get the byte array of the picture
    [byte[]]$jpg = Get-Content $picture -encoding byte
 
    #change the active directory property
    $user.put("thumbnailPhoto",  $jpg )
    $user.setinfo()

    Write-Host $user.displayname " updated" -ForegroundColor Green
} else {
    Write-Host $username " Does not exist" -ForegroundColor Red
}

 

These steps work for SharePoint 2013 and SharePoint 2010 from CU December 2011.

Minimize JavaScript and CSS – Web Essentials

When working on a Website or Intranet environment and you are using a lot off JavaScript and CSS files you would like to have the possibility to minimize/bundle the files.

On the web you can find a lot of solutions for this, on my last project when I was working on a website based on SharePoint 2013 (http://www.motion10.nl). I found a great extension for Visual Studio called: Web Essentials.

Key features of this extension are:

  • Bundling of JavaScript and CSS files.
  • Minimize files.

 

The extension does much more for example it also display’s a color swatch next to a specified color in you Stylesheet file Glimlach .

CSS Class

For a complete list off the features you can look on the website of Web Essentials.

The extension gives you the option to minimize a JavaScript files by clicking on it with your second mouse button. Once generated it keeps synching your changes to the minimized file (so you will keep working in the normal file).

 

Minimize files

All of the settings of the extension can be managed from the default options menu within the “Web Essentials” category that the extension adds.

Options

In my opinion this extension should be added to the list of items you install on a development environment.

Retrieve the Friendly URL of a Publishing Page

One of my first projects with SharePoint 2013 is building a SharePoint website. For the website we had to build a functionality that display’s the URL of specific pages.

For the website we are using Managed Navigation. Displaying URLs meant we wanted to display the friendly URLS. After searching for a while with ILSpy and looking at some MSDN articles:

I found out that the friendly URL can be retrieved by first getting a list of NavigationTerm items from a SharePoint list item. When you have a NavigationTerm you can retrieve the display URL of that term using the method “GetResolvedDisplayUrl”.

In short the code to retrieve the friendly URLs will look something like this.

public List<string> GetPagesUrls() {
    
    //list for saving the urls
    List<string> retVal = new List<string>();

    //current web
    SPWeb web = SPContext.Current.Web;

    //check if the current web is a publishing weg
    if (PublishingWeb.IsPublishingWeb(web)) {

        //get the pages list id
        Guid listId = PublishingWeb.GetPagesListId(web);

        //retrieve the pages list
        SPList pagesList = web.Lists[listId];

        //itterate trough the pages
        foreach (SPListItem item in pagesList.Items) {
            //retrieve the terms used for the navigation (this can be multiple terms)
            IList<NavigationTerm> terms = TaxonomyNavigation.GetFriendlyUrlsForListItem(item, false);

            string url = string.Empty;

            //check if the pages has terms associated with it
            if (terms.Count > 0) {
                //use the GetResolvedDisplayUrl to retrieve the page friendly urls
                url = terms[0].GetResolvedDisplayUrl(string.Empty);
            } else {
                //if the page does not have any terms get the normal url
                url = item.File.Url;
            }

            retVal.Add(url);
        }
    }
    return retVal;
}

Behold the new SharePoint Splash screen

With the new version of SharePoint 2013 that was released on MSDN last week as you can read here SharePoint 2013 has a new Installation screen to give power to the new Interface of SharePoint 2013.

SharePoint 2013 Splash

Today I will start a new fresh installation of a development machine with the following specifications:

  • Microsoft Office 2013 Professional.
  • Microsoft Office Visio 2013.
  • Microsoft Office Project 2013.
  • Visual Studio 2012.
  • Windows Server 2012.
  • SQL Server 2012.

Every interesting thing I will discover will be posted on this blog, so stay tuned!

SharePoint 2013 Reaches RTM

The Office engineering team signed off on a new Build. The build they signed off for is RTM. This means SharePoint 2013 will be able to be downloaded in less than a month from now on TechNet or MSDN.

sharepoint-2013

You can read all about it on the Office News site: http://blogs.office.com/b/office-news/archive/2012/10/11/office-reaches-rtm.aspx

Some interesting point from the news article are:

Additionally, we have a number of programs that provide business customers with early access so they can begin testing, piloting and adopting Office within their organizations:

  • We will begin rolling out new capabilities to Office 365 Enterprise customers in our next service update, starting in November through general availability.
  • Volume Licensing customers with Software Assurance will be able to download the Office 2013 applications as well as other Office products including SharePoint 2013, Lync 2013 and Exchange 2013 through the Volume Licensing Service Center by mid-November. These products will be available on the Volume Licensing price list on December 1.
  • IT professionals and developers will be able to download the final version via their TechNet or MSDN subscriptions by mid-November.

Please stay tuned for more specifics on general availability dates and other Office launch news. In the meantime, if you’d like to give the pre-release version a try, you can visit office.com/preview.

Thank you to the millions of people who have been testing early releases of the new Office. We are grateful for your support. Your invaluable feedback has helped us make the new Office the best Office ever.

SharePoint 2013 Databases without the GUID

When you configure SharePoint 2013 it will create the SharePoint_AdminContent database with a GUID at the end. To keep my database names clean I searched for a solution.

To be able to set the name of the database you will have to perform the configuration with PowerShell.

Take the following steps:

1. Open SharePoint 2013 Management Shell as Administrator.

2. Type the following:

New-SPConfigurationDatabase -DatabaseName BETA_SP2013_Config –AdministrationContentDatabaseName BETA_SP2013_AdminContent –DatabaseServer SP2013DB -FarmCredentials (get-credential)

3. You will get a pop-up to fill in the farm credentials. Fill in the account you want to use to run central administration under. When you filled in the account the management shell will also ask you to fill in the passphrase for joining servers to your farm.

4. Install the help collection files by running the following script.

Install-SPHelpCollection –All

5. Initialize the SharePoint Security by running the following script.

Initialize-SPResourceSecurity

6. Register the SharePoint Services by running the following script.

Install-SPService

7. Create central administration by running the following script.

New-SPCentralAdministration -Port 5555 -WindowsAuthProvider “ntlm”

8. Install the application content by running the following script.

Install-SPApplicationContent

9. When everything is done. You performed the steps the configuration wizard does for you. To be absolutely sure that everything is configured run the configuration wizard.

 

After these steps SharePoint is configured with a clean database name!

Almost all other SharePoint databases can be named trough the UI only the Search Service Application and the Usage service create there own databases. The solution is to also create these services  with PowerShell.

In other for you to create the Search Service Application you can use the script below (You only have to change the arguments on the top).

$databaseServer = "SP2013DB"
$ServiceAppPool = "SharePoint Services Application Pool"
$IndexLocation = "C:\SP2013_Search"
$SearchServiceApplicationName = "Search Service Application"
$server = "CLAY"

Write-Host "Setting up Search"

Start-SPEnterpriseSearchServiceInstance $server
Start-SPEnterpriseSearchQueryAndSiteSettingsServiceInstance $server

$searchApp = New-SPEnterpriseSearchServiceApplication -Name $SearchServiceApplicationName -ApplicationPool $ServiceAppPool -DatabaseServer $databaseServer -DatabaseName "BETA_SP2013_Search"
$searchInstance = Get-SPEnterpriseSearchServiceInstance $server

$ssa = Get-SPEnterpriseSearchServiceApplication 

Write-Host "Setup Topology"
$ssa.ActiveTopology
$clone = $ssa.ActiveTopology.Clone()

New-SPEnterpriseSearchAdminComponent –SearchTopology $clone -SearchServiceInstance $searchInstance
New-SPEnterpriseSearchContentProcessingComponent –SearchTopology $clone -SearchServiceInstance $searchInstance
New-SPEnterpriseSearchAnalyticsProcessingComponent –SearchTopology $clone -SearchServiceInstance $searchInstance 
New-SPEnterpriseSearchCrawlComponent –SearchTopology $clone -SearchServiceInstance $searchInstance 
New-SPEnterpriseSearchIndexComponent –SearchTopology $clone -SearchServiceInstance $searchInstance -RootDirectory $IndexLocation
New-SPEnterpriseSearchQueryProcessingComponent –SearchTopology $clone -SearchServiceInstance $searchInstance

$clone.Activate()

$ssa | get-SPEnterpriseSearchAdministrationComponent |  set-SPEnterpriseSearchAdministrationComponent -SearchServiceInstance  $searchInstance


Write-Host "Setup Proxy"
$searchAppProxy = New-SPEnterpriseSearchServiceApplicationProxy -Name "$SearchServiceApplicationName Proxy" -SearchApplication $SearchServiceApplicationName > $null

Write-Host "Done"

 

You need to take the steps below to create the Usage Service Application:

1. Get the Usage Service.

$serviceInstance = Get-SPUsageService

2. Create the service application.

New-SPUsageApplication -Name "Usage Service Application -DatabaseServer SP2013DB -DatabaseName "BETA_SP2013_UsageDB" -UsageService $serviceInstance > $null

3.  Get the proxy off the application and provision it.

$usa = Get-SPServiceApplicationProxy | where {$_.TypeName -like "Usage*"} 
$usa.Provision()