Showing posts with label SharePoint. Show all posts
Showing posts with label SharePoint. Show all posts

Thursday, June 6, 2013

SharePoint 2010 and the Chrome JavaScript Bug

This issue is also known as the missing scrollbar bug, because the vertical scrollbar does not appear in Chrome when the problem happens.  However the scrollbar is just a symptom of a larger problem going on with the page and this article provides a work around.

The Problem

When viewing SharePoint 2010 from the Chrome browser, intermittently the page will load but fail to call it’s JavaScript initialization functions leaving the page only partially functional.  Abnormalities include:

  • Parts of the ribbon bar may be unresponsive
  • The vertical scrollbar is apparently missing
  • Many native SharePoint JavaScript libraries don’t load including: sp.js and sp.core.js
  • Any JavaScript functions registered to execute after page load with the ExecuteOrDelayUntilScriptLoaded, or the _spBodyOnLoadFunctionNames methods do not get called
The Cause

From what I can tell, the problem is caused by this piece of JavaScript found in the SharePoint page source that references the search box.

image

Search Initialization Code
  1. // append an onload event handler
  2. var S3031AEBB__onload = document.body.onload;
  3. if (typeof document.body.onload == 'function') {
  4.     document.body.onload = function () {
  5.         S3031AEBB__onload();
  6.         document.getElementById('ctl00_PlaceHolderSearchArea_ctl01_S3031AEBB_InputKeywords').name = 'InputKeywords';
  7.     }
  8. }
  9. else {
  10.     document.body.onload = function () {
  11.         eval(S3031AEBB__onload);
  12.         document.getElementById('ctl00_PlaceHolderSearchArea_ctl01_S3031AEBB_InputKeywords').name = 'InputKeywords';
  13.     }
  14. }

This code is crudely appending an initialization function to the body tag onload attribute.  By looking at the SharePoint body tag we can see why this is a sensitive area because it is where the _spBodyOnLoadWrapper function is registered.  The _spBodyOnLoadWrapper function is responsible for starting a chain of events that initializes the behavior of the page once it has finished downloading.

SharePoint 2010 Body Tag
  1. <body scroll="no" onload="if (typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();" class="v4master">

Why does this only break Chrome?  I suspect what is happening is that the Chrome browser has a different way of interpreting the code and corrupts the body.onload attribute.  Decided by a race condition, this happens sometimes before the page has the opportunity to execute the body load event.  When this happens, the _spBodyOnLoadWrapper function never executes and therefore a dozen client systems usually running in the background of a SharePoint page never initialize.

The Work Around

I read some people had success by removing the search box completely from the masterpage.  This did not work for me and the possibility of removing the search box is not always an option for many environments.  I also saw many solutions which required including the jQuery library on the page.  While I have nothing against jQuery, I don’t like this solution because it relies on including an entire external library on every page load unnecessarily.  My solution accomplishes the same task using SharePoint’s native Microsoft Ajax.

Put this code at the bottom of the master page file just before the closing body tag.

Work Around Code Block
  1. <script type="text/javascript">
  2.     /*****************
  3.      *  
  4.      * Code to handle the SharePoint / Chome bug
  5.      *
  6.      *****************/
  7.  
  8.     function chromeNudge() {
  9.         /// <summary>
  10.         /// If SharePoints body onload handler has not fired yet
  11.         /// this function calls it manually
  12.         /// </summary>
  13.         if (!_spBodyOnLoadCalled) {
  14.             if (window.console) {
  15.                 window.console.log('Chrome Bug: _spBodyOnLoadWrapper did not fire, calling manually.');
  16.             }
  17.             _spBodyOnLoadWrapper();
  18.         }
  19.     }
  20.  
  21.     function chromeNudgeDelay() {
  22.         /// <summary>
  23.         /// If the current browser is Chrome, set a Timeout
  24.         /// to call chromeNudge to at that time evaluate
  25.         /// whether the onload wrapper needs a "nudge"
  26.         /// </summary>
  27.         if (navigator && navigator.userAgent && /chrome/.test(navigator.userAgent.toLowerCase())) {
  28.             setTimeout(chromeNudge, 250);
  29.         }
  30.     }
  31.  
  32.     // call chromeNudgeDelay after MS Ajax init event (aka body load)
  33.     Sys.Application.add_init(chromeNudgeDelay);
  34.  
  35. </script>

The chromeNudgeDelay function executes after the body load event when MS Ajax calls it.  It first checks that the browser is Chrome.  If it is, it then sets a timeout to delay a quarter of a second before calling chromeNudge.  This timeout gives the page the opportunity to load correctly without intervention.  The chromeNudge function then executes and examines the page to see if _spBodyOnLoadWrapper did already execute.  If it has not, chromeNudge calls the _spBodyOnLoadWrapper function itself, and the page loads as it is supposed to.

I consider this to be a hack, but I like it better than rewriting Microsoft’s code in this case.

Friday, November 28, 2008

MOSS Barcode Image Timing Out in Large Document Libraries

I'm working with a few large libraries in our SharePoint farm, one of which is well over 200,000 documents and climbing.  In these libraries, we have the barcode policy turned on, however on the DispForm.aspx page for viewing a document's properties, the barcode image never loads.  Eventually after about 5 minutes, it will timeout and show a broken link like this.

brokenbarcode

In the web front end event log, this error is recorded:

0x0234  Windows SharePoint Services  Database  8sli  Monitorable    
List item query elapsed time: 371854 milliseconds, Additional data 
(if available): Query HRESULT: 80131530 List internal name, flags, 
and URL: {GUID}, flags=0x0000000004c01088, 
URL=https://[hostname]/_layouts/barcodeimagefromitem.aspx?
doc=[DocGuid]&list=[ListGuid]

After troubleshooting, searching the web, and dealing with Microsoft support all to no gain, it was decided to break a best practice and overwrite one of Microsoft's layout pages, namely the troublesome barcodeimagefromitem.aspx. To this I want to give many props to my colleague, Jamie Burkholder, who did much of the work on this fix. This is the solution we arrived at.

If you view the source for this layout page, it's not much to look at.  It primarily links to a code behind page, that we don't have the code for, so the only option is to rename the page to barcodeimagefromitem.old.aspx so we can create our own page.

Here is the code we used to replace the original.

<%@ Page language="c#" %>

<%@ Assembly Name="Microsoft.Office.Policy, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>

<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<%@ Import Namespace="System.Diagnostics" %>
<%@ Import Namespace="System.Drawing" %>
<%@ Import Namespace="System.Drawing.Imaging" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.Office.RecordsManagement" %>
<%@ Import Namespace="Microsoft.Office.RecordsManagement.PolicyFeatures" %>


<script runat="server">
     
        
        #region "Event Handlers"
     
        //----------------------------------------------
        //  Event Handlers
        //----------------------------------------------
     
        void Page_Load(object sender, System.EventArgs e)
       {
           string listId = Request["List"].ToString();         // collect the list guid from URL
           string docId = Request["Doc"].ToString();                // collect the doc guid from URL
           string barCodeValue = "";
    
           Guid uidListId = new Guid(listId);
           SPList targetList = null;
           SPListItem item;
           System.Drawing.Image    barCodeImage = null;
    
           
           // get list from the guid
           targetList = SPContext.Current.Web.Lists[uidListId];
                   
           // Lookup the document
           if (targetList != null)
           {
               item = targetList.GetItemByUniqueId(new Guid(docId)); 
               
               if (item != null)
               {
                   barCodeValue = Barcode.GetBarcodeValue(item);
                   barCodeImage = Barcode.GetBarcodeImage(item);  
               }
    
               Response.ContentType = "image/jpeg";
               barCodeImage.Save(Response.OutputStream, ImageFormat.Jpeg);
           }
       }    
       
       #endregion
       
</script> <html xmlns="http://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title></title> </head> <body> <form id="form1" runat="server"> </form> </body> </html>

While developing this code, we were able to recreate the same timeout issue as the Microsoft version.  Here is what happened.  Originally, when we were collecting the SPListItem from the SharePoint API we used this line:

item = targetList.Items[new Guid(docId)];        /* Never use this!!!!! */

This works fine until you start putting thousands of documents in the same library.  When this happens, this line will timeout and you will never get your list item.  However, Microsoft knew what they were doing and they gave us an alternative to this that performs like a champ even when there are hundreds of thousands of list items.  Here is the example:

item = targetList.GetItemByUniqueId(new Guid(docId));

This is a solid work around until Microsoft patches the bug, however remember when modifying these layout pages that Microsoft will likely come along and overwrite your work with the next patch.

Best Regards,

-Mark Gabriel

Saturday, November 8, 2008

MOSS 2007 Document Properties Link in Search Results

For over a year I was frustrated with the lack of a link to a document's properties in SharePoint search results. Currently, the out of the box results provides only a link to the document itself, not the metadata or properties. In fact, it is quit difficult for an average user to go from the search results to the document properties. An other blog had an excellent solution to this that provided a link to the containing folder of the document. From here you can simply drop down the menu for the document and select View Properties. While this works for small libraries, in the situation when you have hundreds of other files in that parent folder, this solution becomes less attractive. After a couple frustrating attempts and having to sit down and learn about XSLT and XPath functions, now I have found a solution to this. As in the example pictured above, you can create a link in the search results to get to the properties of a document. The trick is to be able to build the URL using XPath functions in XSL. Here is an example of such a URL.

http://gabrieldev1/Docs/Documents/Forms/DispForm.aspx?ID=2

Create a Metadata Property Mapping

The first thing we need is the ID number which refers to the unique ID of the document for that library. We therefore must create a Metadata Property Mapping for this.

  • Open up the Shared Services Administration.
  • Click Search Settings -> Metadata property mappings -> New Managed Property Fill out the form like this:
  • Click OK and perform a Full Index on all relevant content sources.

You have now successfully created and populated the needed metadata property mapping, now we need to pull that value into our search results.

Add The New Metadata Property to the Core Search Results Web Part

  • In your Search Center, go to the results.aspx page.
  • Click Site Actions -> Edit Page
  • On the Core Results Webpart, click Edit -> Modify Shared Webpart
  • In the Core Results Webpart properties, click the + next to Results Query Option
  • Look for the section labeled Selected Columns, Click the "..." button next to this field to open up the XML editor
  • You will see a window that looks like this
  • Add this Column to the XML:
    <Column Name="ListItemID"/>
  • This is an example of what your XML should look like when you are done:
    <root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <Columns>
        <Column Name="WorkId"/>
        <Column Name="Rank"/>
        <Column Name="Title"/>
        <Column Name="Author"/>
        <Column Name="Size"/>
        <Column Name="Path"/>
        <Column Name="Description"/>
        <Column Name="Write"/>
        <Column Name="SiteName"/>
        <Column Name="CollapsingStatus"/>
        <Column Name="HitHighlightedSummary"/>
        <Column Name="HitHighlightedProperties"/>
        <Column Name="ContentClass"/>
        <Column Name="IsDocument"/>
        <Column Name="PictureThumbnailURL"/>
        <Column Name="ListItemID"/>
      </Columns>
    </root>

 

Add the Link to the Core Search Results XSL Template

You now have the ID variable available to you in the XSL Template for the Search Results. Now we need to edit this template to display the link.

  • In the Core Search Results Properties, click the XSL Editor button.
  • Another window with a bunch of poorly indented XML will appear. I recommend you take the time to copy this into visual studio or other XML text editor.
  • Scroll down until you find the remark
    <!-- This template is called for each result -->
  • Below this remark is a list of variable declarations, add sitename, listitemid, and isdocument declarations to this list so that the code looks like this:
    <!-- This template is called for each result -->
    <xsl:template match="Result">
      <xsl:variable name="id" select="id"/>
      <xsl:variable name="url" select="url"/>
      <xsl:variable name="sitename" select="sitename"/>
      <xsl:variable name="listitemid" select="listitemid"/>
      <xsl:variable name="isdocument" select="isdocument"/>
  • Now that the variables are initialized for the Template, we must construct the URL to the document properties page.
          <!-- BEGIN Add Link to document properties -->
          <xsl:choose>
            <xsl:when test="isdocument[. != 0]">
              <span class="srch-Description">
                |
              </span>
              <span class="srch-URL">
                <a href="{$sitename}/{substring-before(substring-after(substring($url, string-length($sitename)), '/'), '/')}/Forms/DispForm.aspx?ID={$listitemid}">
                  Properties
                </a>
              </span>
            </xsl:when>
          </xsl:choose>
          <!-- END Add Link to document properties -->

Here is the entire XSL template that I used in this example:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:param name="ResultsBy" />
<xsl:param name="ViewByUrl" />
<xsl:param name="ViewByValue" />
<xsl:param name="IsNoKeyword" />
<xsl:param name="IsFixedQuery" />
<xsl:param name="ShowActionLinks" />
<xsl:param name="MoreResultsText" />
<xsl:param name="MoreResultsLink" />
<xsl:param name="CollapsingStatusLink" />
<xsl:param name="CollapseDuplicatesText" />
<xsl:param name="AlertMeLink" />
<xsl:param name="AlertMeText" />
<xsl:param name="SrchRSSText" />
<xsl:param name="SrchRSSLink" />
<xsl:param name="ShowMessage" />
<xsl:param name="IsThisListScope" />
<xsl:param name="DisplayDiscoveredDefinition" select="True" />
<xsl:param name="NoFixedQuery" />
<xsl:param name="NoKeyword" />
<xsl:param name="NoResults" />
<xsl:param name="NoResults1" />
<xsl:param name="NoResults2" />
<xsl:param name="NoResults3" />
<xsl:param name="NoResults4" />
<xsl:param name="DefinitionIntro" />
 
<!-- When there is keywory to issue the search -->
<xsl:template name="dvt_1.noKeyword">
  <span class="srch-description">
  <xsl:choose>
  <xsl:when test="$IsFixedQuery">
      <xsl:value-of select="$NoFixedQuery" />
  </xsl:when>
   <xsl:otherwise>
      <xsl:value-of select="$NoKeyword" />
   </xsl:otherwise>
  </xsl:choose>
  </span>       
</xsl:template>
 
 
<!-- When empty result set is returned from search -->
<xsl:template name="dvt_1.empty">
 <div class="srch-sort">
  <xsl:if test="$AlertMeLink and $ShowActionLinks">  
    <span class="srch-alertme" > <a href ="{$AlertMeLink}" id="CSR_AM1" title="{$AlertMeText}"><img style="vertical-align: middle;" src="/_layouts/images/bell.gif" alt="" border="0"/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$AlertMeText" /></a>
    </span>
  </xsl:if>
 
  <xsl:if test="string-length($SrchRSSLink) &gt; 0 and $ShowActionLinks">     
   <xsl:if test="$AlertMeLink">  
    |
   </xsl:if>
   <a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="SRCHRSSL"><img style="vertical-align: middle;" border="0" src="/_layouts/images/rss.gif" alt=""/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$SrchRSSText"/></a>
  </xsl:if>
 </div>
 <br/> <br/>
 
  <span class="srch-description" id="CSR_NO_RESULTS">
   <xsl:value-of select="$NoResults" />
 
    <ol>
    <li><xsl:value-of select="$NoResults1" /></li>
    <li><xsl:value-of select="$NoResults2" /></li>
    <li><xsl:value-of select="$NoResults3" /></li>
    <li><xsl:value-of select="$NoResults4" /></li>
    </ol>
  </span>
</xsl:template>
 
 
<!-- Main body template. Sets the Results view (Relevance or date) options -->
<xsl:template name="dvt_1.body">
  <div class="srch-results">
  <xsl:if test="$ShowActionLinks">
  <div class="srch-sort"> <xsl:value-of select="$ResultsBy" /> 
   <xsl:if test="$ViewByUrl">  
     | 
    <a href ="{$ViewByUrl}" id="CSR_RV" title="{$ViewByValue}">              
     <xsl:value-of select="$ViewByValue" />
    </a>  
   </xsl:if>
   <xsl:if test="$AlertMeLink">  
     | 
    <span class="srch-alertme" > <a href ="{$AlertMeLink}" id="CSR_AM2" title="{$AlertMeText}"><img style="vertical-align: middle;" src="/_layouts/images/bell.gif" alt="" border="0"/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$AlertMeText" /></a>
    </span>
   </xsl:if>
   <xsl:if test="string-length($SrchRSSLink) &gt; 0">  
     | 
     <a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="SRCHRSSL"><img style="vertical-align: middle;" border="0" src="/_layouts/images/rss.gif" alt=""/><xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text><xsl:value-of select="$SrchRSSText"/></a>
   </xsl:if>
  </div>
  <br /><br />
  </xsl:if>
  <xsl:apply-templates />
 
  </div>  
  <xsl:call-template name="DisplayMoreResultsAnchor" />
</xsl:template><!-- This template is called for each result -->
<xsl:template match="Result"> 
  <xsl:variable name="id" select="id"/>
  <xsl:variable name="url" select="url"/>
  <xsl:variable name="sitename" select="sitename"/>
  <xsl:variable name="listitemid" select="listitemid"/>
  <xsl:variable name="isdocument" select="isdocument"/>
  <span class="srch-Icon"> 
   <a href="{$url}" id="{concat('CSR_IMG_',$id)}" title="{$url}">
   <img align="absmiddle" src="{imageurl}" border="0" alt="{imageurl/@imageurldescription}" />
   </a>
  </span>
  <span class="srch-Title">
   <a href="{$url}" id="{concat('CSR_',$id)}" title="{$url}">
    <xsl:choose>
     <xsl:when test="hithighlightedproperties/HHTitle[. != '']">
         <xsl:call-template name="HitHighlighting">
          <xsl:with-param name="hh" select="hithighlightedproperties/HHTitle" /> 
         </xsl:call-template>   
     </xsl:when>
     <xsl:otherwise><xsl:value-of select="title"/></xsl:otherwise> 
    </xsl:choose>
   </a>
    <br/> 
   </span>
 
   <xsl:choose>
     <xsl:when test="$IsThisListScope = 'True' and contentclass[. = 'STS_ListItem_PictureLibrary'] and picturethumbnailurl[. != '']">
       <div style="padding-top: 2px; padding-bottom: 2px;">
        <a href="{$url}" id="{concat('CSR_P',$id)}" title="{title}">
          <img src="{picturethumbnailurl}" alt="" />
        </a>
       </div>
     </xsl:when>
   </xsl:choose>
   <div class="srch-Description">
    <xsl:choose>
    <xsl:when test="hithighlightedsummary[. != '']">
       <xsl:call-template name="HitHighlighting">
          <xsl:with-param name="hh" select="hithighlightedsummary" /> 
       </xsl:call-template> 
    </xsl:when>   
     <xsl:when test="description[. != '']">
        <xsl:value-of select="description"/>     
     </xsl:when>     
    </xsl:choose>
    </div >
    <p class="srch-Metadata">
    <span class="srch-URL">
      <!-- BEGIN Add Link to document properties -->
      <xsl:choose>
        <xsl:when test="isdocument[. != 0]">
          <span class="srch-URL">
            <a href="{$sitename}/{substring-before(substring-after(substring($url, string-length($sitename)), '/'), '/')}/Forms/DispForm.aspx?ID={$listitemid}">
              Properties
            </a>
          </span>
          <span class="srch-Description">
            |
          </span>
        </xsl:when>
      </xsl:choose>
      <!-- END Add Link to document properties -->
     <a href="{$url}" id="{concat('CSR_U_',$id)}" title="{$url}" dir="ltr">      
      <xsl:choose>
        <xsl:when test="hithighlightedproperties/HHUrl[. != '']">
           <xsl:call-template name="HitHighlighting">
              <xsl:with-param name="hh" select="hithighlightedproperties/HHUrl" /> 
           </xsl:call-template> 
        </xsl:when>
       <xsl:otherwise><xsl:value-of select="url"/></xsl:otherwise> 
      </xsl:choose>
     </a>
    </span>           
     <xsl:call-template name="DisplaySize">
      <xsl:with-param name="size" select="size" />
     </xsl:call-template>     
     <xsl:call-template name="DisplayString">
      <xsl:with-param name="str" select="author" /> 
     </xsl:call-template>  
     <xsl:call-template name="DisplayString">
      <xsl:with-param name="str" select="write" />
     </xsl:call-template>     
     <xsl:call-template name="DisplayCollapsingStatusLink">
        <xsl:with-param name="status" select="collapsingstatus"/>
        <xsl:with-param name="urlEncoded" select="urlEncoded"/>
        <xsl:with-param name="id" select="concat('CSR_CS_',$id)"/>
     </xsl:call-template>        
    </p>
</xsl:template>
 
<xsl:template name="HitHighlighting"> 
 <xsl:param name="hh" /> 
 <xsl:apply-templates select="$hh"/> 
</xsl:template>
 
<xsl:template match="ddd"> 
  &#8230;  
</xsl:template> 
<xsl:template match="c0"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c1"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c2"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c3"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c4"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c5"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c6"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c7"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c8"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
<xsl:template match="c9"> 
    <b><xsl:value-of select="."/></b>
</xsl:template> 
 
 
<!-- The size attribute for each result is prepared here -->
<xsl:template name="DisplaySize">
  <xsl:param name="size" /> 
  <xsl:if test='string-length($size) &gt; 0'>       
   <xsl:if test="number($size) &gt; 0">
   -
    <xsl:choose>
     <xsl:when test="round($size div 1024) &lt; 1"><xsl:value-of select="$size" /> Bytes</xsl:when>
     <xsl:when test="round($size div (1024 *1024)) &lt; 1"><xsl:value-of select="round($size div 1024)" />KB</xsl:when>
     <xsl:otherwise><xsl:value-of select="round($size div (1024 * 1024))"/>MB</xsl:otherwise>
    </xsl:choose>    
   </xsl:if>
  </xsl:if>
</xsl:template>
 
 
 
<!-- A generic template to display string with non 0 string length (used for author and lastmodified time -->
<xsl:template name="DisplayString">
  <xsl:param name="str" />
  <xsl:if test='string-length($str) &gt; 0'>   
   - 
   <xsl:value-of select="$str" /> 
  </xsl:if>
</xsl:template>
 
<!-- document collapsing link setup -->
<xsl:template name="DisplayCollapsingStatusLink">
    <xsl:param name="status"/>
    <xsl:param name="urlEncoded"/>
    <xsl:param name="id"/>
    <xsl:if test="$CollapsingStatusLink">
      <xsl:choose>
          <xsl:when test="$status=1">
              <br/>
              <xsl:variable name="CollapsingStatusHref" select="concat(substring-before($CollapsingStatusLink, '$$COLLAPSE_PARAM$$'), 'duplicates:&quot;', $urlEncoded, '&quot;', substring-after($CollapsingStatusLink, '$$COLLAPSE_PARAM$$'))"/>
              <span class="srch-dup">
              [<a href="{$CollapsingStatusHref}" id="$id" title="{$CollapseDuplicatesText}">
              <xsl:value-of select="$CollapseDuplicatesText"/>
              </a>]
              </span>
          </xsl:when>
      </xsl:choose>
    </xsl:if>
</xsl:template><!-- The "view more results" for fixed query -->
<xsl:template name="DisplayMoreResultsAnchor">
  <xsl:if test="$MoreResultsLink">
   <a href="{$MoreResultsLink}" id="CSR_MRL">
    <xsl:value-of select="$MoreResultsText"/> 
    </a>
   </xsl:if>
</xsl:template>
 
<xsl:template match="All_Results/DiscoveredDefinitions">
  <xsl:variable name="FoundIn" select="DDFoundIn" />
  <xsl:variable name="DDSearchTerm" select="DDSearchTerm" />
  <xsl:if test="$DisplayDiscoveredDefinition = 'True' and string-length($DDSearchTerm) &gt; 0">
    <script language="javascript">
     
          function ToggleDefinitionSelection()
          {
            var selection = document.getElementById("definitionSelection");
            if (selection.style.display == "none")
            {
              selection.style.display = "inline";
            }
            else
            {
             selection.style.display = "none";
            }
         }
       
</script>
    <div>
      <a href="#" onclick="ToggleDefinitionSelection(); return false;">
        <xsl:value-of select="$DefinitionIntro" /><b><xsl:value-of select="$DDSearchTerm"/></b></a>
      <div id="definitionSelection" class="srch-Description" style="display:none;">
        <xsl:for-each select="DDefinitions/DDefinition">
          <br/>
          <xsl:variable name="DDUrl" select="DDUrl" />
          <xsl:value-of select="DDStart"/>
          <b>
            <xsl:value-of select="DDBold"/>
          </b>
          <xsl:value-of select="DDEnd"/>
          <br/>
          <xsl:value-of select="$FoundIn"/>
          <a href="{$DDUrl}">
          <xsl:value-of select="DDTitle"/> 
          </a>
        </xsl:for-each>
      </div>
    </div>
  </xsl:if>   
</xsl:template>
 
<!-- XSL transformation starts here -->
<xsl:template match="/">
  <xsl:if test="$AlertMeLink">  
   <input type="hidden" name="P_Query" />
   <input type="hidden" name="P_LastNotificationTime" />
  </xsl:if>
  <xsl:choose>
   <xsl:when test="$IsNoKeyword = 'True'" >
    <xsl:call-template name="dvt_1.noKeyword" />
   </xsl:when>
   <xsl:when test="$ShowMessage = 'True'">
     <xsl:call-template name="dvt_1.empty" />
   </xsl:when>
   <xsl:otherwise>
    <xsl:call-template name="dvt_1.body"/>      
   </xsl:otherwise>
  </xsl:choose>
</xsl:template> 
 
<!-- End of Stylesheet -->
</xsl:stylesheet>

Hopefully someone else out there will find this as useful as I have, or someone will laugh and comment on how it would have been so much easier to do it a different way! If this is the case, please post it!!

Until next time.

-Mark Gabriel