Home > SharePoint > MOSS 2007 CQWP Item style customization

MOSS 2007 CQWP Item style customization

2012/04/21

In my previous post i wrote about the implementation of custom fields for search and display.

Now we would to modify the link that by default for a Document library open the file in the same page (is generated an anchor with target=”_self”) so the user is constrained to click the back button for return to MOSS; and in this case the customer hates the paging , so he want to see all records but constrained in a scrolling window (otherwise the page layout is screwed) : easy to do with an XSLT web part by modifying the generated XSLT in the page with SharePoint Designer; a bit complicated with a CQWP.

Here we must operate on the internal mechanism of XSLT rendering : this is done by opening with the Designer the main site collection , where we can modify the base styles.

At this level we see the “Style Library” folder:


where we find the ItemStyle.xsl , inside it we can put our custom transformations.

In the CQWP properties on the web page we have a Styles section:


Where are listed default styles: these styles are implemented in ItemStyle.xsl, opening the file we see a list of <xsl:template where we can find the items listed on the web interface, for example


Is not clear where are mapped the internal names with the user interface names , for example ImageTopCentered = “Image on top, centered”; but are all meaningful except the Item Style Default which is not immediate to think is the UI equivalent “Image on left”.

More informations in this page.

In order to implement a custom style we can start from copying a default style (“Default”, for example…) , but before this i show some XSLT tricks.

The Item Style, as the word is suggesting, is called for every row of our data; in XSLT we can know when we are working with the beginning and when we are at the end of data.

We know that the current is the first row of data with the syntax

<xsl:if test="count(preceding-sibling::*)=0"> 
</xsl:if>

And that the current is the last row of data with

<xsl:if test="count(following-sibling::*)=0"> 
</xsl:if>

If you need to use the ddwrt functions (FormatDateTime, for example) must be inserted the following namespace attribute to the root xsl:stylesheet element in ItemStyle

xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView

and below, before the first xsl:template (Default):

<xsl:param name="PageUrl" />  

The customer requests are to download the file by clicking on the Document Library item which is coming from another site collection, and the data must flows in a window with height 150px, so we can write this code:

    <xsl:template name="substring-before-last">
      <xsl:param name="string1" select="''" />
      <xsl:param name="string2" select="''" />
      <xsl:if test="$string1 != '' and $string2 != ''">
        <xsl:variable name="head" select="substring-before($string1, $string2)" />
        <xsl:variable name="tail" select="substring-after($string1, $string2)" />
        <xsl:value-of select="$head" />
        <xsl:if test="contains($tail, $string2)">
          <xsl:value-of select="$string2" />
          <xsl:call-template name="substring-before-last">
            <xsl:with-param name="string1" select="$tail" />
            <xsl:with-param name="string2" select="$string2" />
          </xsl:call-template>
        </xsl:if>
      </xsl:if>
    </xsl:template>
 
    <xsl:template name="BADocLink" match="Row[@Style='BADocLink']" mode="itemstyle">
        <xsl:variable name="SafeLinkUrl">
            <xsl:call-template name="OuterTemplate.GetSafeLink">
                <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="SafeImageUrl">
            <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
                <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="DisplayTitle">
            <xsl:call-template name="OuterTemplate.GetTitle">
                <xsl:with-param name="Title" select="@Title"/>
                <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="LinkTarget">
            <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
        </xsl:variable>
        <xsl:variable name="ToolTipCI" select="@BA" />
        <xsl:variable name="DetailPageLink" select="@LinkUrl" />
        <!-- Get the filename <xsl:variable name="extension" select="tokenize(@LinkFilename, '\.')[last()]"/> not available, no xsl 2.0 in moss 2007 -->
                
        <xsl:variable name="LinkFileBaseName">
            <xsl:call-template name="substring-before-last">
                <xsl:with-param name="string1" select="@LinkFilename" />
                <xsl:with-param name="string2" select="'.'" />
            </xsl:call-template>
        </xsl:variable>
                    
        <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
        
        <xsl:variable name="tableStart">
            <xsl:if test="count(preceding-sibling::*)=0">
                    <![CDATA[                 
                    <div id='divWrapCqwpA1' style='overflow: auto; overflow-x:hidden; height: 150px'>
                        <table ID="tblBaCqwp" width="100%" border="0" cellpadding="2" cellspacing="0"> 
                            <tr id="trWrapCqwpA1" height="20px">
                                <th class="ms-vh" width="100%" nowrap="" style="padding-top:3px; padding-left:6px"><a style="color:#999999; font-family:Tahoma; font-style:normal; font-size:11px;font-weight:normal;">Title</a></th>
                            </tr>
                        ]]>
            </xsl:if>
        </xsl:variable>
 
        <xsl:variable name="tableEnd">   
            <xsl:if test="count(following-sibling::*)=0">
                  <![CDATA[</div></table>]]>
            </xsl:if>     
        </xsl:variable>
 
        <xsl:value-of select="$tableStart" disable-output-escaping="yes"/>
 
        <tr>
            <td style="width:40%" class="item link-item" nowrap="nowrap">
               <a href="{$DetailPageLink}" target="_blank" title="{$ToolTipCI}"><xsl:value-of select="$LinkFileBaseName"/></a> 
            </td> 
        </tr> 
        
        <xsl:value-of select="$tableEnd" disable-output-escaping="yes"/>
    </xsl:template>      

Examining this code , we see that we can we can implement custom XSLT fuctions (“substring-before-last”) in Styles.xls : the drawback is that these functions will be listed in the web interface in the Styles section, but we can survive to this.

We cannot use XSL 2.0 functions, only 1.0: for example “tokenize” is an XSL 2.0 function that we can’t use.

In this case we need the “substring-before-last” function because the field @LinkFilename comes with the file extension, in the default view of a Document Library this extension is automatically stripped, in this case we must provide the extension stripping with a custom function, so we obtain the XSLT variable LinkFileBaseName which is the @Linkfilename without the extension.

With “preceding-sibling” we know when is coming the first row of data so this is the moment for the table headers generation: in this case we insert the div with height 150 where our table will be constrained, inserting some id that will be useful.

The block is inserted in a CDATA because without it the div with id “divWrapCqwpA1” is not closed and in the web page you will have an rendering error; instead with the CDATA you can insert not well formed HTML tags.

For the table items we need to open the item so we symply use the @LinkUrl in the href, with the needed target =”_blank”, displaying the file name without extension.

As seen for the header, when the data are terminated (following-sibling) we inject the closing </div></table>.

After saving our Styles.xsl we can see in the Styles for the web part our custom implementation:


Note: ItemStyle.xsl needs to be checked out in order to do changes, when is saved it is needed to be checked in as a major version: otherwise the new styles are not available for not administrator users, the Style property specify the new style but users are rerouted to the Default because they don’t see the new Style in list.

But there is a problem: ok the table is constrained into the div, but when we scroll the data the table header row goes away; here we can resume a Internet Explorer only trick: insert a CEWP with this code:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> 
 
><style type="text/css">
   .DataGridFixedHeader { position: relative; top: expression(this.offsetParent.scrollTop);}
</style>
 
<script type="text/javascript">
    $().ready(function(){
       $("#trWrapCqwpA1").addClass("DataGridFixedHeader");
    }); 
</script>

where we assign a CSS class to the table header (i have assigned a id,trWrapCqwpA1 , for avoiding complex searches in DOM) ; with this code the table header remain fixed while the data scrolls in the div.

If is needed to access to the item properties instead of the download of the file we can use this template (applied to my specific case , but it should not be a problem to adapt to other cases):

<xsl:template name="BAItemEdit" match="Row[@Style='BAItemEdit']" mode="itemstyle">
        <xsl:variable name="SafeLinkUrl">
            <xsl:call-template name="OuterTemplate.GetSafeLink">
                <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="SafeImageUrl">
            <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
                <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="DisplayTitle">
            <xsl:call-template name="OuterTemplate.GetTitle">
                <xsl:with-param name="Title" select="@Title"/>
                <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="LinkTarget">
            <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
        </xsl:variable>
        <xsl:variable name="IDPath" select="concat('ID=',@ID)" />
        <xsl:variable name="ToolTipCI" select="@BA" />
        <xsl:variable name="DetailPageLink" select="concat(substring-before($PageUrl,'/BA/default.aspx'), '/CorporateIdentity/Forms/DispForm.aspx?', $IDPath, '&amp;Source=', $PageUrl)" />
        
        <xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
        
        <xsl:variable name="tableStart">
            <xsl:if test="count(preceding-sibling::*)=0">
                    <![CDATA[                 
                    <div id='divWrapCqwpA1' style='overflow: auto; overflow-x:hidden; height: 150px'>
                        <table ID="tblBaCqwp" width="100%" border="0" cellpadding="2" cellspacing="0"> 
                            <tr id="trWrapCqwpA1" height="20px">
                                <th class="ms-vh" width="100%" nowrap="" style="padding-top:3px; padding-left:6px"><a style="color:#999999; font-family:Tahoma; font-style:normal; font-size:11px;font-weight:normal;">Title</a></th>
                            </tr>
                                
                            ]]>
                    </xsl:if>
        </xsl:variable>
 
        <xsl:variable name="tableEnd">   
            <xsl:if test="count(following-sibling::*)=0">
                <![CDATA[</table></div>]]>
            </xsl:if>     
        </xsl:variable>
 
        <xsl:value-of select="$tableStart" disable-output-escaping="yes"/>
 
        <tr>
            <td style="width:40%" class="item link-item" nowrap="nowrap">
                <a href="{$DetailPageLink}" target="_self" title="{$ToolTipCI}"><xsl:value-of select="@Title"/></a> 
            </td> 
        </tr> 
        
        <xsl:value-of select="$tableEnd" disable-output-escaping="yes"/>
    </xsl:template>  

In this case we are constructing a link to the dispform.aspx page of the other Document Library , where we can eventually edit or delete the item.

Note that in this template we use $PageUrl , a variable automatically available if we insert the namespace

xmlns:ddwrt=http://schemas.microsoft.com/WebParts/v2/DataView in the declarations

<xsl:stylesheet 
  version="1.0" 
  exclude-result-prefixes="x d xsl msxsl cmswrt"
  xmlns:x="http://www.w3.org/2001/XMLSchema" 
  xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" 
  xmlns:cmswrt="http://schemas.microsoft.com/WebParts/v3/Publishing/runtime"
  xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
  <xsl:param name="PageUrl" /> ...

We need it for the querystring parameter “Source” , by specifying it when the user closes the outside DispForm.aspx it will be returned to the page specified in this querystring argument, and $PageUrl contains the address of the current page.

Using custom styles we can debug some problems, for example if we have a doubt on field names we can use this template

<xsl:template name="CQWP_FieldNames" match="Row[@Style='CQWP_FieldNames']" mode="itemstyle">
<xsl:for-each select="@*">
P:<xsl:value-of select="name()" />
</xsl:for-each>
</xsl:template> 

that dumps the field names , with a P: prefix (or whatever you want) ,so you can see what are the real fields names .

Advertisements
Categories: SharePoint
%d bloggers like this: