Wednesday, February 29, 2012

Select multiple Refiners via the UI with xsl & js (part 2)

Just by extending the XSL of the Refinement Panel and adding a little javascript it is possible to select multiple Refiners via the UI:


After selection of multiple Refiners:


Add the following javascript to the Search results page:
<script type="text/javascript">
function Filter(url)
{
var inputs = document.getElementsByTagName("input");
var idValues = [];
for (var i = 0; i < inputs.length; i++) {   
  if ((inputs[i].type == "checkbox") && (inputs[i].checked)) {
idValues.push((GetUrlKeyValue("r",false,inputs[i].value)).substr((GetUrlKeyValue("r",false,url)).length));
}}
window.location = SP.Utilities.UrlBuilder.replaceOrAddQueryString(url, "r", GetUrlKeyValue("r",false,url)+decodeURI(idValues.toString().replace(/\,/g,"%20")));
}
</script>
(2012-03-01) Correction: changed the boolean value in all three GetUrlKeyValue functions to false.

Extend the XSL of the Filterlink template in the Refinement Panel web part:
  <xsl:template name="FilterLink">
    <xsl:param name="Url"/>
    <xsl:param name="UrlTooltip"/>
    <xsl:param name="Value"/>
    <xsl:param name="FilterSelection"/>
    <xsl:param name="ShowCounts"/>
    <xsl:param name="Count"/>
    <xsl:param name="Percentage"/>
    <xsl:param name="Indentation"/>
    <!-- HW -->
    <xsl:param name="ManagedProperty" />
    <!-- HW -->
    <xsl:variable name="SecureUrl">
      <xsl:call-template name="GetSecureUrl">
        <xsl:with-param name="Url" select="$Url" />
      </xsl:call-template>
    </xsl:variable>
    <li class="ms-searchref-filter {$FilterSelection}">
      <xsl:if test="($Indentation = '1')">
        <span class="ms-searchref-indenticon">&#8627;&#160;</span>
      </xsl:if>
      <!-- HW -->
      <xsl:if test="($ManagedProperty = 'Author' or $ManagedProperty = 'FileExtension') and $FilterSelection != 'ms-searchref-unselected' and not(starts-with($Value, 'Any '))">
        <input name="{$Value}" type="checkbox" align="center" title="OR {$Value}" value="{$SecureUrl}" checked="yes" />
      </xsl:if>
      <xsl:if test="($ManagedProperty = 'Author' or $ManagedProperty = 'FileExtension') and $FilterSelection = 'ms-searchref-unselected' and not(starts-with($Value, 'Any '))">
        <input name="{$Value}" type="checkbox" align="center" title="OR {$Value}" value="{$SecureUrl}" />
      </xsl:if>
      <xsl:choose>
        <xsl:when test="(starts-with($Value, 'Any Result Type') or starts-with($Value, 'Any Author')) and $FilterSelection != 'ms-searchref-unselected'">
          <a href="javascript:Filter('{$SecureUrl}')"><img align="absmiddle" src="/_layouts/images/filter.gif" border="0" title="Join selected Refiners"/></a>
        </xsl:when>
        <xsl:when test="(starts-with($Value, 'Any Result Type') or starts-with($Value, 'Any Author')) and $FilterSelection = 'ms-searchref-unselected'">
          <a href="{$SecureUrl}"><img align="absmiddle" src="/_layouts/images/filteroff.gif" border="0" title="Reset selected Refiners"/></a>
        </xsl:when>
        <xsl:when test="starts-with($Value, 'Any ')">
          <img align="absmiddle" src="/_layouts/images/asterisk.png" border="0" />
        </xsl:when>
        <xsl:when test="$ManagedProperty = 'SiteName'">
          <a href="http://{$Value}" target="_blank" title="Open site in new window"><img align="absmiddle" src="/_layouts/images/SharePointFoundation16.png" border="0" /></a>
        </xsl:when>
        <xsl:when test="ddwrt:MapToIcon('', $Value) != 'icgen.gif'">
          <img align="absmiddle" src="/_layouts/images/{ddwrt:MapToIcon('', $Value)}" border="0" />
        </xsl:when>
        <xsl:when test="$Value = 'Word'">
          <img align="absmiddle" src="/_layouts/images/icdocx.png" border="0" />
        </xsl:when>
        <xsl:when test="$Value = 'Excel'">
          <img align="absmiddle" src="/_layouts/images/icxlsx.png" border="0" />
        </xsl:when>
        <xsl:when test="$Value = 'PowerPoint'">
          <img align="absmiddle" src="/_layouts/images/icpptx.gif" border="0" />
        </xsl:when>
        <xsl:when test="$Value = 'Webpage'">
          <img align="absmiddle" src="/_layouts/images/icaspx.gif" border="0" />
        </xsl:when>
        <xsl:when test="$ManagedProperty = 'Author'">
          <a href="/SearchCenter/Pages/peopleresults.aspx?k={$Value}" target="_blank" title="Search for user profile"><img align="absmiddle" src="/_layouts/images/ACA16.gif" border="0" /></a>
        </xsl:when>
        <xsl:otherwise>
          <img align="absmiddle" src="/_layouts/images/{$Value}.gif" onError="this.src='/_layouts/images/bullet.gif';" border="0" />
        </xsl:otherwise>
      </xsl:choose>
      <xsl:text> </xsl:text>
      <!-- HW -->
      <a class="ms-searchref-filterlink" href="{$SecureUrl}" title="{$RefineByHeading}: {$UrlTooltip}">
        <xsl:value-of select="Value"/>
      </a>
      <xsl:choose>
        <xsl:when test="($ShowCounts = 'Count') and ($Count != '')">
          <span class="ms-searchref-count">
            <xsl:if test="$IsRTL = 'True'">&#x200f;</xsl:if> 
            (<xsl:value-of select="Count"/>)
          </span>
        </xsl:when>
        <xsl:when test="($ShowCounts = 'Percentage') and ($Percentage != '')">
          <span class="ms-searchref-count">
            <xsl:if test="$IsRTL = 'True'">&#x200f;</xsl:if> 
            (<xsl:value-of select="format-number($Percentage, '0%')"/>)
          </span>
        </xsl:when>
      </xsl:choose>
    </li>
  </xsl:template>

That's all folks!

Notice: The Display Language should be English, because I check for the word 'Any' in the XSL. You can/should adjust this by yourself in rows 30, 33, 36 for your preferred language.

Zip file with two webparts:
- HTML Form Web Part.dwp with navigation and the javascript;
- Refinement Panel.webpart with the extended XSL and customized categories.
Add the web parts to the Left Zone in the Search results page, and remove the original Refinement Panel web part.

References:
- See how to propagate the ManagedProperty parameter;
- Working with URLs in SharePoint 2010 JavaScripts;
- Helpful SharePoint JavaScript functions.

Wednesday, February 22, 2012

Select multiple Refiners in the same category (part 1)

The selection of multiple Refiners in the same category is possible out of the box.


For instance if we select the Word refiner in the Result Type category it will show us the following url:

According to the Keyword Query Syntax Reference Multiple Property Restrictions work like this: When you use multiple instances of the same property restriction, matches are based on the union of the property restrictions in the keyword query. This is functionally the same as using the OR Boolean operator.
So if we just add "%20fileextension%3D%22pdf%22" to the URL it will get us Word OR Pdf documents as a result.


The nice thing is that the XSL recognizes both refiners as selected.


Even the deselection of a selected refiner is working.
In this case, if we would deselect the Word refiner, the url is correct:
http://sp2010/SearchCenter/Pages/results.aspx?k=sharepoint&r=fileextension%3D%22pdf%22
But on the other hand if we would deselect the Pdf refiner the logic is broken. When multiple instances of the same property are used -like Word- the url is not correctly processed: the spaces (OR) are replaced by AND. This will show us no results of course.

Another example of selection of multiple refiners is with the Author category. The author can/will show us 2 names: the original author from the document property, and the one that created the document (by upload).


First we select the original author of the document.

Then we select the creator of the document.


The deselection of a selected author is working fine.

Conclusion:
So the selection of multiple refiners in the same category is possible but the UI doesn't provide the full and correct navigation for it.

In part 2 I will try to overcome this.