Monday, October 28, 2013

Adding Taxonomy Field to a Content Type or a SPList – SharePoint 2013

Managed metadata is a hierarchical collection of centrally managed terms that we can define, and then use as attributes for items. Taxonomy term stores are created through the SharePoint Central Administration and consist of managed metadata Groups, Term Sets, and Terms.

In here Terms can be divided into two types.

Managed terms: created by users and often organized into a hierarchy.
Enterprise keywords: words or phrases that are added to SharePoint items. All enterprise keywords are part of a single, non-hierarchical term set.

SharePoint Server 2013 includes a predefined column named Enterprise Keywords. We can add this column to content types or lists. When a user adds a value to the Enterprise Keywords column, the enterprise keyword control is displayed. Enterprise keywords control allows users to select enterprise keywords in addition to managed terms and by default it allows for multiple values.

Enterprise Keywords column can be added to a content type by using follow PowerShell function:

function AddTaxonomyFieldInContentTypes([string]$listname, [string]$weburl){
 $web=get-spweb $weburl
 $targetlist=$web.lists[$listname]
 if( $targetlist -ne $null){
   $entField=$targetlist.Fields | where {$_.title -eq "Enterprise Keywords"}
   if($entField -ne $null){
      $targetlist.Fields.Delete($entField);
   }
   $newField=$web.AvailableFields| where {$_.title -eq "Enterprise Keywords"}
   $targetlist.ContentTypes | foreach {
      if($_.name -ne "Folder"){
         $_.FieldLinks.Add($newField); $_.Update()
      }
   }          
   $targetlist.Update();
 } else {
    write-host "$listname list is empty"
 }
}

Enterprise Keywords column can be added to a list by using follow PowerShell function:


function AddTaxonomyFieldInLists([string]$listname, [string]$weburl){
 $web=get-spweb $weburl
 $targetlist=$web.lists[$listname]
 if( $targetlist -ne $null){
   $entField=$targetlist.Fields | where {$_.title -eq "Enterprise Keywords"}
   if($entField -ne $null){
      $targetlist.Fields.Delete($entField);
   }
   $newField=$web.AvailableFields| where {$_.title -eq "Enterprise Keywords"}
   $targetlist.Fields.Add($newField);
   $targetlist.Update();
   try{
     $view = $targetlist.DefaultView
     if(!$view.ViewFields.ToStringCollection().Contains($newField))
     {
       $view.ViewFields.add($newField)
       $view.Update()
     }
     write-host "$listname list and view Updated"
   } catch {
     write-host "$listname Failed to Update View field."
   }  
 } else {
   write-host "$listname list is empty"
 }
}

Wednesday, October 2, 2013

Localizing Content Search Webpart Display Templates in SharePoint 2013

In a previous post, I wrote about a way to parameterize the search query in Content Search Webparts. The method actually resolves some filter criteria in the query text before content is rendered in the CSWP: SharePoint 2013 Content Search Web Part (CSWP) in Variation Sites.

As part of the same task I wanted to localize some hardcoded content rendered in the CSWP. Even though it seemd CSWPs support localization because of the CustomStrings.js javascript reference added in the display template, I could hardly find a reference on how to use it, syntax, etc.

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

So here is the way. CustomStrings.js by default contains 2 entries and comment at the top asks to add custom localized strings to use in display templates.

// Add your custom localized strings and then include these string dictionaries in your display templates using the $includeLanguageScript function

$registerResourceDictionary("en-ca", {
    "sampleCustomStringId": "Sample custom string",   
    "rf_RefinementTitle_ManagedPropertyName": "Sample Refinement Title for ManagedPropertyName"
});

Therefore the Step 1 is to add localized strings to the CustomStrings.js files and to make sure they are deployed to the master page gallery of the site in the Language files folder. We have to deploy such a file for each culture we want to support.

$registerResourceDictionary("en-ca", {
    "sampleCustomStringId": "Sample custom string",
    "PostedOn": "Posted on",
    "ReadMore": "Read More",
    "rf_RefinementTitle_ManagedPropertyName": "Sample Refinement Title for ManagedPropertyName"
});

Then in the display template we have to make sure CustomStrings.js is referenced using the $includeLanguageScript function.

And lastly, in order to reference a key from the CustomStrings file, we can create variables like:
var readMoreText = $resource("ReadMore");
var postedOnText = $resource("PostedOn");

Defined variables can be used as:
<a href="_#= linkURL =#_" class="btn_more">_#=  readMoreText =#_</a>

Complete body section of the Item Template:
<body>
<!--
 Warning: Do not try to add HTML to this section. Only the contents of the first <div> inside the <body> tag will be used while executing Display Template code. Any HTML that you add to this section will NOT become part of your Display Template.
-->
<script>
    $includeLanguageScript(this.url, "~sitecollection/_catalogs/masterpage/Display Templates/Language Files/{Locale}/CustomStrings.js");
</script>

<!--
    Use the div below to author your Display Template. Here are some things to keep in mind:
    * Surround any JavaScript logic as shown below using a "pound underscore" (#_ ... _#) token inside a comment.

    * Use the values assigned to your variables using an "underscore pound equals"
    (_#= ... =#_) token.
-->

<div id="TwoLines">
<!--#_
var monthname = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec");
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";

var readMoreText = $resource("ReadMore");
var postedOnText = $resource("PostedOn");
_#-->
 <div id="_#= containerId =#_" data-displaytemplate="Item2Lines">
  <div class="NewsRight" id="_#= dataContainerId =#_">
   <div id="_#= line1Id =#_"> _#= postedOnText =#_
    <label>_#= monthname[new Date(line1).getMonth()] + " " + new Date(line1).getDate()+ ", "+new Date(line1).getFullYear() =#_</label>
   </div>
              
<!--#_
if(!line2.isEmpty)
{
_#-->
   <div class="Award_Itm_Link" id="_#= line2Id =#_" >
    <a href="_#= linkURL =#_" title="_#= $htmlEncode(line1.defaultValueRenderer(line1)) =#_" id="_#= line1LinkId =#_">_#= line2 =#_</a>
   </div>
<!--#_
}
_#-->
   <a href="_#= linkURL =#_" class="btn_more">_#= readMoreText =#_</a>   
  </div>
  <br class="clearfloat" />
 </div>
</div>
</body>