Me & My SharePoint [FrontEnd]

© Christian Stahl – All about SharePoint branding & customizations

Image slideshow with CQWP in SharePoint 2010 — August 9, 2011

Image slideshow with CQWP in SharePoint 2010

This post is a follow up to the past 3 part series ‘Display News pages with CQWP’. In the last post (Part 3) I wrote about how to slide the news items one by one from right to left with the Content By Query Web Part (CQWP) and with help of jQuery.

In this post I will show how to use a similar technique but we’re now going to create an image slideshow that reads images from an image library in SharePoint. To achieve this I have used a slideshow plugin that support many types of effects, it also supports stuff like pause on hover, auto fit, click triggers and much more.


This blog do not cover how to configure the CQWP or the basics of modifying ItemStyle.xsl ContentQueryMain.xsl or other XSL files that describes the CQWP, we´re going straight to the core for the fun stuff which means XSLT, CSS and jQuery. Please read the previous posts for more information about options for created date, the count word function and the layout.

Some things to consider:

  • By this example you need to modify ContentQueryMain.xsl. Changes in this file will affect all templates in ItemStyle.xsl, therefor I recommend you to create a copy of ContentQueryMain.xsl and ItemStyle.xsl and modify these copies separately.
  • If you prefer you can create a provisioning module with Visual Studio 2010, a feature that pushes the copies and the web part into proper folders, but this is a SPD blog, so I will show how to do this by SharePoint Designer 2010.
  • When JS is used for DOM manipulation, all the content could show up shortly when the page loads, before the DOM is fully loaded. This can be solved by CSS or jQuery, in this example I have simply used a fixed height for the container where the images displays.
  • The images will be displayed from the thumbnail directory in the Picture Library, so you don’t need to think about loading time for full size images.
  • Content Query web part is only available in SharePoint Server.

Let´s go!

Now create a standard Picture Library in SharePoint and upload a couple of images, type a title for each image. Go to a page in your SharePoint environment and add a Content Query Web Part (CQWP). Open the tool pane. Expand Query and click ‘Show items from the following list’. Select the picture library you just created. Click the OK button. Verify that you see the images onto the page, and then click the Web Part arrow and select Export. Save it on the desktop. You can now delete the Content Query Web Part on the page and close the page. Later on we going to do some changes in this file and upload it, let’s come back to that.

Download jQuery Cycle Plugin here and the latest jQuery, upload the files to Style library.

Open your custom master page and type the proper reference to latest jQuery and to the cycle plugin, for example

<!-- Custom Scripts -->
<script type="text/javascript" src="/Style Library/Scripts/jquery-1.6.min.js"></script>
<script type="text/javascript" src="/Style Library/Scripts/jquery.cycle.all.js"></script> 

In the head section of the master page, copy and paste this script, remember that this plugin allows lots of cool effects more than this

<!-- Image Cycle -->
<script type="text/javascript">
$(document).ready(function() {
    $('.slideshow').cycle({
		fx: 'fade', 
		speed: 3000,
		timeout:3000,
		random:  1
	});
});
</script>

Copy and paste this CSS classes into your custom CSS file

/* --- CYCLE JQUERY --- */
.slideshow {position:relative;height:170px;overflow: hidden;}
.slideshow img {display:block;height:143px;padding:5px;border:1px solid #ccc;background-color:#eee;}
.SlideshowText {padding-left:5px;margin-bottom:10px;height:20px;}

Publish the master page and the CSS file and create a copy of ItemStyle.xsl check it out and rename this to ItemStyleImageCycle.xsl. In this file you’ll need only one template, so open jthe file and delete all its content. Copy and paste the following xslt stylesheet.

<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="ItemsHaveStreams">
    <xsl:value-of select="'False'" />
  </xsl:param>
  <xsl:variable name="OnClickTargetAttribute" select="string('javascript:this.target=&quot;_blank&quot;')" />
  <xsl:variable name="ImageWidth" />
  <xsl:variable name="ImageHeight" />
 
<!-- CycleImage Template -->
    <xsl:template name="CycleImage" match="Row[@Style='CycleImage']" 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:if test="string-length($SafeImageUrl) != 0"> 
                    <a href="{$SafeLinkUrl}">
                      <xsl:if test="$ItemsHaveStreams = 'True'">
                        <xsl:attribute name="onclick">
                          <xsl:value-of select="@OnClickForWebRendering"/>
                        </xsl:attribute>
                      </xsl:if>
                      
                      <xsl:if test="$ItemsHaveStreams != 'True' and @OpenInNewWindow = 'True'">
                        <xsl:attribute name="onclick">
                          <xsl:value-of disable-output-escaping="yes" select="$OnClickTargetAttribute"/>
                        </xsl:attribute>
                      </xsl:if>  
                 <img class="image" src="{$SafeImageUrl}" title="{@ImageUrlAltText}"><br />
                 <div class="SlideshowText"><xsl:value-of select="@Title"/></div>
                        <xsl:if test="$ImageWidth != ''">
                          <xsl:attribute name="width">
                            <xsl:value-of select="$ImageWidth" />
                          </xsl:attribute>
                        </xsl:if>
                        <xsl:if test="$ImageHeight != ''">
                          <xsl:attribute name="height">
                            <xsl:value-of select="$ImageHeight" />
                          </xsl:attribute>
                        </xsl:if>
                        
                      </img>
                    </a>
            </xsl:if>
    </xsl:template> 
</xsl:stylesheet>

When you have checked in and published this file, create a copy of ContentQueryMain.xsl. check it out and rename this to ContentQueryMainImageCycle.xsl. Open this file and copy and paste the following xsl stylesheet.

<xsl:stylesheet
    version="1.0"
    exclude-result-prefixes="x xsl cmswrt cbq" 
    xmlns:x="http://www.w3.org/2001/XMLSchema"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:cmswrt="http://schemas.microsoft.com/WebPart/v3/Publishing/runtime"
    xmlns:cbq="urn:schemas-microsoft-com:ContentByQueryWebPart">
    <xsl:output method="xml" indent="no" media-type="text/html" omit-xml-declaration="yes"/>
    <xsl:param name="cbq_isgrouping" />
    <xsl:param name="cbq_columnwidth" />
    <xsl:param name="Group" />
    <xsl:param name="GroupType" />
    <xsl:param name="cbq_iseditmode" />
    <xsl:param name="cbq_viewemptytext" />
    <xsl:param name="cbq_errortext" />
    <xsl:param name="SiteId" />
    <xsl:param name="WebUrl" />
    <xsl:param name="PageId" />
    <xsl:param name="WebPartId" />
    <xsl:param name="FeedPageUrl" />
    <xsl:param name="FeedEnabled" />
    <xsl:param name="SiteUrl" />
    <xsl:param name="BlankTitle" />
    <xsl:param name="BlankGroup" />
    <xsl:param name="UseCopyUtil" />
    <xsl:param name="DataColumnTypes" />
    <xsl:param name="ClientId" />
    <xsl:param name="Source" />
    <xsl:param name="RootSiteRef" />
    <xsl:param name="CBQPageUrl" />
    <xsl:param name="CBQPageUrlQueryStringForFilters" />
    

	<!--No UL start-->
  <xsl:variable name="BeginList" select="string()" />
	<!--No end UL-->
  <xsl:variable name="EndList" select="string()" />
	<!--No LI start-->
  <xsl:variable name="BeginListItem" select="string()" />
	<!--No LI end-->
  <xsl:variable name="EndListItem" select="string()" />
  
  
<xsl:template match="/">
        <xsl:call-template name="OuterTemplate" />
</xsl:template>



<xsl:template name="OuterTemplate">
        <xsl:variable name="Rows" select="/dsQueryResponse/Rows/Row" />
        <xsl:variable name="RowCount" select="count($Rows)" />
        <xsl:variable name="IsEmpty" select="$RowCount = 0" />
           
            <div id="{concat('cbqwp', $ClientId)}" class="cbq-layout-main">
                 <xsl:if test="$cbq_iseditmode = 'True' and string-length($cbq_errortext) != 0">
                    <div class="wp-content description">
                        <xsl:value-of disable-output-escaping="yes" select="$cbq_errortext" />
                    </div>
                  </xsl:if>
                  <xsl:choose>
                      <xsl:when test="$IsEmpty">
                           <xsl:call-template name="OuterTemplate.Empty" >
                               <xsl:with-param name="EditMode" select="$cbq_iseditmode" />
                           </xsl:call-template>
                      </xsl:when>
                      <xsl:otherwise>
                           <xsl:call-template name="OuterTemplate.Body">
                               <xsl:with-param name="Rows" select="$Rows" />
                               <xsl:with-param name="FirstRow" select="1" />
                               <xsl:with-param name="LastRow" select="$RowCount" />
                          </xsl:call-template>
                      </xsl:otherwise>
                  </xsl:choose>
            </div>
            
            <xsl:if test="$FeedEnabled = 'True' and $PageId != ''">
                <div class="cqfeed">
                    <xsl:variable name="FeedUrl1" select="concat($SiteUrl,$FeedPageUrl,'xsl=1&amp;web=',$WebUrl,'&amp;page=',$PageId,'&amp;wp=',$WebPartId,'&amp;pageurl=',$CBQPageUrl,$CBQPageUrlQueryStringForFilters)" />
                    <a href="{cmswrt:RegisterFeedUrl( $FeedUrl1, 'application/rss+xml')}"><img src="\_layouts\images\rss.gif" border="0" alt="{cmswrt:GetPublishingResource('CbqRssAlt')}"/></a>
                </div>
            </xsl:if>
    </xsl:template>


 
<xsl:template name="OuterTemplate.Empty">
        <xsl:param name="EditMode" />
            <xsl:if test="$EditMode = 'True' and string-length($cbq_errortext) = 0">
                <div class="wp-content description">
                    <xsl:value-of disable-output-escaping="yes" select="$cbq_viewemptytext" />
                </div>
            </xsl:if>
</xsl:template>
    
<xsl:template name="OuterTemplate.Body">
      <xsl:param name="Rows" />
      <xsl:param name="FirstRow" />
      <xsl:param name="LastRow" />
      

		<!--Div and class - no UL and id-->
      <xsl:variable name="BeginColumn1" select="string('&lt;div class=&quot;slideshow&quot; style=&quot;width:')" />
      <xsl:variable name="BeginColumn2" select="string('%&quot; &gt;')" />
      <xsl:variable name="BeginColumn" select="concat($BeginColumn1, $cbq_columnwidth, $BeginColumn2)" />
		<!--End Div - No end UL-->
      <xsl:variable name="EndColumn" select="string('&lt;/div&gt;')" />
      
      <xsl:for-each select="$Rows">
            <xsl:variable name="CurPosition" select="position()" />
            <xsl:if test="($CurPosition &gt;= $FirstRow and $CurPosition &lt;= $LastRow)">
                <xsl:variable name="StartNewGroup" select="@__begingroup = 'True'" />
                <xsl:variable name="StartNewColumn" select="@__begincolumn = 'True'" />
                <xsl:choose>
                    <xsl:when test="$cbq_isgrouping != 'True'">
                        <xsl:if test="$CurPosition = $FirstRow">
                            <xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
                        </xsl:if>
                    </xsl:when>
                    <xsl:when test="$StartNewGroup and $StartNewColumn">
                        <xsl:choose>
                            <xsl:when test="$CurPosition = $FirstRow">
                                <xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
                                <xsl:call-template name="OuterTemplate.CallHeaderTemplate"/>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
                                <xsl:value-of disable-output-escaping="yes" select="concat($EndColumn, $BeginColumn)" />
                                <xsl:call-template name="OuterTemplate.CallHeaderTemplate"/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:when>
                    <xsl:when test="$StartNewGroup">
                        <xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
                        <xsl:call-template name="OuterTemplate.CallHeaderTemplate"/>
                    </xsl:when>
                    <xsl:when test="$StartNewColumn">
                        <xsl:choose>
                            <xsl:when test="$CurPosition = $FirstRow">
                                <xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of disable-output-escaping="yes" select="concat($EndColumn, $BeginColumn)" />
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:when>
                    <xsl:otherwise>
                    </xsl:otherwise>
                </xsl:choose>
                <xsl:call-template name="OuterTemplate.CallItemTemplate">
                    <xsl:with-param name="CurPosition" select="$CurPosition" />
                </xsl:call-template>
                <xsl:if test="$CurPosition = $LastRow">
                  <xsl:if test="$cbq_isgrouping = 'True'">
                    <xsl:call-template name="OuterTemplate.CallFooterTemplate"/>
                  </xsl:if>
                  <xsl:value-of disable-output-escaping="yes" select="$EndColumn" />
                </xsl:if>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
   
   
   
   

    <xsl:template name="OuterTemplate.CallHeaderTemplate">
      <xsl:value-of disable-output-escaping="yes" select="$BeginListItem" />
      <xsl:apply-templates select="." mode="header">
        </xsl:apply-templates>
      <xsl:value-of disable-output-escaping="yes" select="$BeginList" />
    </xsl:template>
    <xsl:template name="OuterTemplate.CallItemTemplate">
    <xsl:param name="CurPosition" />
      <xsl:value-of disable-output-escaping="yes" select="$BeginListItem" />
      <xsl:choose>
              <xsl:when test="@Style='NewsRollUpItem'">
                  <xsl:apply-templates select="." mode="itemstyle">
                     <xsl:with-param name="EditMode" select="$cbq_iseditmode" />
                  </xsl:apply-templates>
              </xsl:when>
              <xsl:when test="@Style='NewsBigItem'">
                  <xsl:apply-templates select="." mode="itemstyle">
                     <xsl:with-param name="CurPos" select="$CurPosition" />
                  </xsl:apply-templates>
              </xsl:when>
              <xsl:when test="@Style='NewsCategoryItem'">
                  <xsl:apply-templates select="." mode="itemstyle">
                     <xsl:with-param name="CurPos" select="$CurPosition" />
                  </xsl:apply-templates>
              </xsl:when>
              <xsl:otherwise>
                  <xsl:apply-templates select="." mode="itemstyle">
                  </xsl:apply-templates>
              </xsl:otherwise>
          </xsl:choose>
      <xsl:value-of disable-output-escaping="yes" select="$EndListItem" />
    </xsl:template>
    <xsl:template name="OuterTemplate.CallFooterTemplate">
      <xsl:value-of disable-output-escaping="yes" select="$EndList" />
      <xsl:value-of disable-output-escaping="yes" select="$EndListItem" />
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetSafeLink">
        <xsl:param name="UrlColumnName"/>
        <xsl:if test="$UseCopyUtil = 'True'">
            <xsl:value-of select="concat($RootSiteRef,'/_layouts/CopyUtil.aspx?Use=id&amp;Action=dispform&amp;ItemId=',@ID,'&amp;ListId=',@ListId,'&amp;WebId=',@WebId,'&amp;SiteId=',$SiteId,'&amp;Source=',$Source)"/>
        </xsl:if>
        <xsl:if test="$UseCopyUtil != 'True'">
            <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
                <xsl:with-param name="UrlColumnName" select="$UrlColumnName"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetTitle">
        <xsl:param name="Title"/>
        <xsl:param name="UrlColumnName"/>
        <xsl:param name="UseFileName" select="0"/>
        <xsl:choose>
           <xsl:when test="string-length($Title) != 0 and $UseFileName = 0">
                <xsl:value-of select="$Title" />
            </xsl:when>
            <xsl:when test="$UseCopyUtil = 'True' and $UseFileName = 0">
                <xsl:value-of select="$BlankTitle" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="FileNameWithExtension">
                    <xsl:call-template name="OuterTemplate.GetPageNameFromUrl">
                        <xsl:with-param name="UrlColumnName" select="$UrlColumnName" />
                    </xsl:call-template>
                </xsl:variable>
                <xsl:choose>
                    <xsl:when test="$UseFileName = 1">
                      <xsl:call-template name="OuterTemplate.GetFileNameWithoutExtension">
                        <xsl:with-param name="input" select="$FileNameWithExtension" />
                      </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$FileNameWithExtension" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.FormatColumnIntoUrl">
        <xsl:param name="UrlColumnName"/>
        <xsl:variable name="Value" select="@*[name()=$UrlColumnName]"/>
        <xsl:if test="contains($DataColumnTypes,concat(';',$UrlColumnName,',URL;'))">
            <xsl:call-template name="OuterTemplate.FormatValueIntoUrl">
                <xsl:with-param name="Value" select="$Value"/>
            </xsl:call-template>
        </xsl:if>
        <xsl:if test="not(contains($DataColumnTypes,concat(';',$UrlColumnName,',URL;')))">
            <xsl:value-of select="$Value"/>
        </xsl:if>
    </xsl:template>
    <xsl:template name="OuterTemplate.FormatValueIntoUrl">
        <xsl:param name="Value"/>
        <xsl:if test="not(contains($Value,', '))">
            <xsl:value-of select="$Value"/>
        </xsl:if>
        <xsl:if test="contains($Value,', ')">
            <xsl:call-template name="OuterTemplate.Replace">
                <xsl:with-param name="Value" select="substring-before($Value,', ')"/>
                <xsl:with-param name="Search" select="',,'"/>
                <xsl:with-param name="Replace" select="','"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.Replace">
        <xsl:param name="Value"/>
        <xsl:param name="Search"/>
        <xsl:param name="Replace"/>
        <xsl:if test="contains($Value,$Search)">
            <xsl:value-of select="concat(substring-before($Value,$Search),$Replace)"/>
            <xsl:call-template name="OuterTemplate.Replace">
                <xsl:with-param name="Value" select="substring-after($Value,$Search)"/>
                <xsl:with-param name="Search" select="$Search"/>
                <xsl:with-param name="Replace" select="$Replace"/>
            </xsl:call-template>
        </xsl:if>
        <xsl:if test="not(contains($Value,$Search))">
            <xsl:value-of select="$Value"/>
        </xsl:if>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetSafeStaticUrl">
        <xsl:param name="UrlColumnName"/>
        <xsl:variable name="Url">
            <xsl:call-template name="OuterTemplate.FormatColumnIntoUrl">
                <xsl:with-param name="UrlColumnName" select="$UrlColumnName"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:value-of select="cmswrt:EnsureIsAllowedProtocol($Url)"/>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetColumnDataForUnescapedOutput">
        <xsl:param name="Name"/>
        <xsl:param name="MustBeOfType"/>
        <xsl:if test="contains($DataColumnTypes,concat(';',$Name,',',$MustBeOfType,';'))">
            <xsl:value-of select="@*[name()=$Name]"/>
        </xsl:if>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetPageNameFromUrl">
        <xsl:param name="UrlColumnName"/>
        <xsl:variable name="Url">
            <xsl:call-template name="OuterTemplate.FormatColumnIntoUrl">
                <xsl:with-param name="UrlColumnName" select="$UrlColumnName"/>
            </xsl:call-template>
        </xsl:variable>
        <xsl:call-template name="OuterTemplate.GetPageNameFromUrlRecursive">
            <xsl:with-param name="Url" select="$Url"/>
        </xsl:call-template>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetPageNameFromUrlRecursive">
        <xsl:param name="Url"/>
        <xsl:choose>
            <xsl:when test="contains($Url,'/') and substring($Url,string-length($Url)) != '/'">
                <xsl:call-template name="OuterTemplate.GetPageNameFromUrlRecursive">
                    <xsl:with-param name="Url" select="substring-after($Url,'/')"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="$Url"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetGroupName">
        <xsl:param name="GroupName"/>
        <xsl:param name="GroupType"/>
        <xsl:choose>
            <xsl:when test="string-length(normalize-space($GroupName)) = 0">
                <xsl:value-of select="$BlankGroup"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:choose>
                    <xsl:when test="$GroupType='URL'">
                        <xsl:variable name="Url">
                            <xsl:call-template name="OuterTemplate.FormatValueIntoUrl">
                                <xsl:with-param name="Value" select="$GroupName"/>
                            </xsl:call-template>
                        </xsl:variable>
                        <xsl:call-template name="OuterTemplate.GetPageNameFromUrlRecursive">
                            <xsl:with-param name="Url" select="$Url"/>
                        </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="$GroupName" />
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.CallPresenceStatusIconTemplate">
        <xsl:if test="string-length(@SipAddress) != 0">
          <span class="presence-status-icon"><img src="/_layouts/images/imnhdr.gif" onload="IMNRC('{@SipAddress}')" ShowOfflinePawn="1" alt="" id="{concat('MWP_pawn_',$ClientId,'_',@ID,'type=sip')}"/></span>
        </xsl:if>
    </xsl:template>
    
    <xsl:template name="OuterTemplate.GetFileNameWithoutExtension">
        <xsl:param name="input"/>
        <xsl:variable name="extension">
          <xsl:value-of select="substring-after($input, '.')"/>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="contains($extension, '.')">
            <xsl:variable name="afterextension">
              <xsl:call-template name="OuterTemplate.GetFileNameWithoutExtension">
                <xsl:with-param name="input" select="$extension"/>
              </xsl:call-template>
            </xsl:variable>
            <xsl:value-of select="concat(substring-before($input, '.'), $afterextension)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:choose>
              <xsl:when test="contains($input, '.')">
                <xsl:value-of select="substring-before($input, '.')"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="$input"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
      
  </xsl:stylesheet>

Save and publish these files. Let´s return to the file you have exported to your desktop, open it with notepad. There’s three properties in this file you need to change

property name=”ItemXslLink”
property name=”MainXslLink”
property name=”Xsl”

Change this three properties:

<property name="ItemXslLink" type="string">/Style Library/XSL Style Sheets/ItemStyleImageCycle.xsl</property>

<property name="MainXslLink" type="string">/Style Library/XSL Style Sheets/ContentQueryMainImageCycle.xsl</property>

<property name="Xsl" type="string">&lt;xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:cmswrt="http://schemas.microsoft.com/WebPart/v3/Publishing/runtime" exclude-result-prefixes="xsl cmswrt x" &gt; &lt;xsl:import href="/Style Library/XSL Style Sheets/Header.xsl" /&gt; &lt;xsl:import href="/Style Library/XSL Style Sheets/ItemStyleImageCycle.xsl" /&gt; &lt;xsl:import href="/Style Library/XSL Style Sheets/ContentQueryMainImageCycle.xsl" /&gt; &lt;/xsl:stylesheet&gt;</property>

Save the file, close it and go to a page in your SharePoint environment. Now, add and upload this file as a web part from your desktop, it will be displayed as Content Query in the imported Web Part folder. Once you got it on the place, check in the page or stop editing.

There are a couple of steps here, so please drop a comment if you got any questions or get stuck. By the way, it’s not only images that can be cycled, in this way you can achieve this for any kind of list objects.

/ Christian

Display News pages with CQWP – Part III — July 18, 2011

Display News pages with CQWP – Part III

This blog shows how to create a news ticker with Content By Query Web Part (CQWP), how you can make items slide from right to left with help of SharePoint Designer 2010. In this example you will modify ItemStyle.xsl and ContentQueryMain.xsl and use a portion CSS.
In Part 1 in this series I wrote about CQWP and how to create a custom template in ItemStyle.xsl and how to use CSS for the styles. In Part 2 I wrote about how to display the latest 5 news by category and how to separate them by tabs.

Click at the image below to activate the video:

This blog do not cover how to configure the CQWP or to modify ItemStyle.xsl or the other XSL files that describes the CQWP, we´re going straight to the core for the fun stuff which means ItemStyle.xsl, ContentQueryMail.xsl, CSS and jQuery.
Please read the previous posts in this series for more related information.

Some things to consider when the slider template is to be built:

  • Modify the structure of ContentQueryMain can affect all other templates in ItemStyle, when you do this you need therefore to customize a copy of ContentQueryMain. In this example were just adding a class name so you don’t need to do that now.
  • Alternative to customize the xsl files you can create modul with Visual Studio, a feature that copies your customized files to style library including a modified version of the CQWP to the web part gallery.

Let´s go!

Download the jQuery plugin called easySlider by CSS globe. Make a reference in your custom master page to this easySlider. Do also reference to latest jQuery in your custom master page.

<script type="text/javascript" src="/Style Library/Scripts/jquery-1.6.min.js"></script>
<script type="text/javascript" src="/Style Library/Scripts/easySlider1.7.js"></script>

Paste following script in the head section of your master page.

<script type="text/javascript">
$(document).ready(function(){	
	
	$(".slider").easySlider({
		auto: true,
		continuous: true,
		nextId: "slider1next",
		prevId: "slider1prev",
		prevText: 		'',
		nextText: 		'',
		speed: 	1000, // 800
		pause:	3000, // 2000
	});
	
});	
</script>

Check out ItemStyle.xsl. Paste following templates into ItemStyle. This example contains two templates, the first one is for limit number of words for the header and the next is the actual sliding template. Publish the file when you’re done.

<!-- Word counter Template -->
<xsl:template name="FirstNWords">
  <xsl:param name="TextData"/>
  <xsl:param name="WordCount"/>
  <xsl:param name="MoreText"/>
  <xsl:choose>
    <xsl:when test="$WordCount &gt; 1 and (string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, '  ')) &gt; 0)">
      <xsl:value-of select="concat(substring-before($TextData, ' '), ' ')" disable-output-escaping="yes"/>
      <xsl:call-template name="FirstNWords">
        <xsl:with-param name="TextData" select="substring-after($TextData, ' ')"/>
        <xsl:with-param name="WordCount" select="$WordCount - 1"/>
        <xsl:with-param name="MoreText" select="$MoreText"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="(string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, '  ')) &gt; 0)">
      <xsl:value-of select="concat(substring-before($TextData, ' '), $MoreText)" disable-output-escaping="yes"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$TextData" disable-output-escaping="yes"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template> 

<!-- Sliding News Template -->
<xsl:template name="SlidingNews" match="Row[@Style='SlidingNews']" 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="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="Created">
            <xsl:value-of select="@Created" />
	</xsl:variable>
	<xsl:variable name="LinkTarget">
		<xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
	</xsl:variable>
	
	<div class="SlidingNewsWrap CQWP-Content">		
		<xsl:value-of select="$Created"/>
		<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}" >
			<xsl:call-template name="FirstNWords">
        		<xsl:with-param name="TextData" select="$DisplayTitle"/>
       			<xsl:with-param name="WordCount" select="7"/>
        		<xsl:with-param name="MoreText" select="'...'"/>
      		</xsl:call-template>
		</a>
	</div> 
	
</xsl:template>

If you want the date to be formatted you can use for example this xsl:value-of select=”ddwrt:FormatDateTime(string(@Created) ,1033 ,’dd MMMM’)” instead of xsl:value-of select=”@Created”, if you use the ddwrt function you have to include xmlns:ddwrt=”http://schemas.microsoft.com/WebParts/v2/DataView/runtime&#8221; in the XSL:Stylesheet defintion in the top of the Itemstyle file.

Check out ContentQueryMain.xsl. Open the file and locate the div with the class name cbq-layout-main. Add the class slider after the cbq-layout-main class.
Don’t forget a blank space between. Publish the file when you’re done.

<div id="{concat('cbqwp', $ClientId)}" class="cbq-layout-main slider">

Here goes the CSS

/* --- QCWP Slider --- */
.CQWP-Content {
width:390px; height:22px;
padding:7px 0px 0px 10px;
font-family:Cambria, Georgia;
font-size:11px;
border-style:none none solid none;
border-width:1px;
border-color:#e5e5e5;  
}
.CQWP-Content a:link, .CQWP-Content a:visited {
color:green;
}
.slider ul, .slider li, .slider li{ 
width:900px;
overflow:hidden;
}

Stay in tune for the next post in this series, I will wrote about how to cycle images from a image library this time. Please drop a comment if you got any questions, Christian

Display News pages with CQWP – Part II — June 10, 2011

Display News pages with CQWP – Part II

In my previous blog (Part 1) I wrote about the Content By Query Web Part (CQWP) and the post showed how to create a custom template in ItemStyle.xsl and how to use CSS for styles. This blog (Part 2) shows how to display the latest 5 news per type of news at the start page and how to extend the web part with jQuery in order to separate different types of news with tabs. In the next part (Part III) I plan to write about how to create a jQuery news roller that loops the news one by one for the CQWP.

Click at the image below to activate the video:

This blog do not cover how to configure the CQWP or to modify ItemStyle.xsl or the other XSL files that describes the CQWP, we´re going straight to the core for the fun stuff which means ItemStyle.xsl, CSS and jQuery. Please read the previous post for more information about options for created date, the count word function and the footer.

Some things to consider when the format is to be built:

  • A site column associated to the content type for the page layout
  • Display the created date and the month abbreviated
  • Count words, the title should be displayed by a max number of words and not be cut off in the middle. If the title is longer than 7 words, three dots should be displayed afterwards
  • Header, with tabs for different types of news
  • Footer, with the link More news

Let’s go!

In this example I have two types of news pages, Internal and External. I added a new site column I called ‘NewsCategory’, a choice type column to the Article Page content type. Finally I added this as a content field into the page layout I used for my news pages in the site collection.

When this is done and you have created some example news and it’s time to open up Itemstyle.xsl and create a new template. You will find the complete templates in the end of this blog. Let’s start with how to create the header with the tabs into the template. I used UL and LI for this.

<!-- First row -->
<xsl:variable name="CurPosition" select="count(./preceding-sibling::*)" />
<xsl:if test="count(preceding-sibling::*)=0"> 
<ul class="CQWP-Header tabs">	
	<li id="NewsLink1"><a href="#">Internal</a></li>
	<li id="NewsLink2"><a href="#">External</a></li>
</ul>
</xsl:if>

We also need to create output for dates and titles. I have separated internal news and external news in two DIVs with different class names, Internal and External. This will be useful when we need to create click events in jQuery for the tabs.

<!-- Internal -->
<xsl:if test="@NewsCategory = 'Internal'">
<div class="Internal CQWP-Content">
		<xsl:value-of select="$Created"/>
		<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}" >
			<xsl:call-template name="FirstNWords">
        		<xsl:with-param name="TextData" select="$DisplayTitle"/>
       			<xsl:with-param name="WordCount" select="7"/>
        		<xsl:with-param name="MoreText" select="'...'"/>
      		</xsl:call-template>
		</a>
</div> 
</xsl:if>
<!-- External -->
<xsl:if test="@NewsCategory = 'External'">
<div class="External CQWP-Content">
		<xsl:value-of select="$Created"/>
		<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}" >
			<xsl:call-template name="FirstNWords">
        		<xsl:with-param name="TextData" select="$DisplayTitle"/>
       			<xsl:with-param name="WordCount" select="7"/>
        		<xsl:with-param name="MoreText" select="'...'"/>
      		</xsl:call-template>
		</a>
</div> 
</xsl:if>

After this it´s time to create functions for the tabs. When the page loads, only Internal news should be displayed, then we need to take care of the click functions for the tabs. In this example I have used FadeTo as effect for the click. Another challenge is to create a background color for an selected tab, as you may know CSS got no pseudo element for ‘selected’, so in this example I have done this with jQuery by adding a class to an element that have been clicked.

Insert this snippet into your custom master page, don´t forget to include a reference to latest jQuery as well.

<script type="text/javascript">
$(document).ready(function() {
 
 // Show and Hide content
  	$(".Internal").show();
  	$(".External").hide();	
  
 // On Click Event first link
 	$('#NewsLink1').click(function() {
    		$('.Internal').fadeTo("normal",0.95);
    		$('.External').hide();
    	return false; 
  	});
 // On Click Event second link
 	$('#NewsLink2').click(function() {
    		$('.External').fadeTo("normal",0.95);
    		$('.Internal').hide();
    	return false; 
  	});

  // Activate the first tab and add the active class + remove & add the active class
	$("ul.tabs li:first").addClass("active").show(); 
	$("ul.tabs li").click(function() {
		$("ul.tabs li").removeClass("active"); 
		$(this).addClass("active"); 
	});

});
</script>

After this it´s time to set the styles with CSS. Copy these classes and paste them in your custom CSS file attached to the master page.

.CQWP-Header, .CQWP-Archive  { 
color:#333;
font-family:Cambria, Georgia;
border-width:1px;
border-color:#bdbdbd;
}
.CQWP-Header {
width:397px;
height:25px;
padding-top:0px;	
padding-bottom:0px;
padding-left:3px;
font-size:12px;
font-weight:bold;  
border-style:solid none dotted none;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e2e2e2', endColorstr='#ebebeb'); 
background: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#e2e2e2)); 
background: -moz-linear-gradient(top,  #ebebeb,  #e2e2e2);
}
.CQWP-Archive {
width:390px;
height:20px;
margin-top:-1px;		
padding-top:5px;
padding-right:10px;	
padding-bottom:0px;
font-size:11px;
text-align:right;
border-style:dotted none solid none;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ebebeb', endColorstr='#e2e2e2'); 
background: -webkit-gradient(linear, left top, left bottom, from(#e2e2e2), to(#ebebeb));
background: -moz-linear-gradient(top,  #e2e2e2,  #ebebeb);
}
.CQWP-Content {
width:390px;
height:22px;
padding-top:7px;	
padding-bottom:0px;
padding-left:10px;
font-family:Cambria, Georgia;
font-size:11px;
color:#333;
border-style:none none solid none;
border-width:1px;
border-color:#e5e5e5;  
background-color:#fff;  
}
.CQWP-Content a:link, .CQWP-Content a:visited {
padding-left:25px;color:green;
}
#NewsLink1	{float:left;margin-right:6px;list-style: none;}
#NewsLink2	{list-style: none;}

ul.tabs {
list-style: none;
border: 1px solid #fff;
}
ul.tabs li {
float:left;
margin:0;
padding:0;
height:24px;
line-height:24px;
border-top:1px solid #e3e3e3;
overflow:hidden;
}
ul.tabs li a {
text-decoration: none;
color:#000;
display:block;
padding:0px 10px 5px 10px;
border-top:1px solid #e3e3e3;
outline: none;
}
ul.tabs li a:hover {
background:#ccc;
border-top:1px solid #e3e3e3;
}	
ul.tabs li.active, ul.tabs li.active a:hover   {
background:#fff;
border-top:1px solid #e3e3e3;
}

Let’ s put this all together, here’s the complete templates for you:

<!-- Begin the word counter Template -->
<xsl:template name="FirstNWords">
  <xsl:param name="TextData"/>
  <xsl:param name="WordCount"/>
  <xsl:param name="MoreText"/>
  <xsl:choose>
    <xsl:when test="$WordCount &gt; 1 and (string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, '  ')) &gt; 0)">
      <xsl:value-of select="concat(substring-before($TextData, ' '), ' ')" disable-output-escaping="yes"/>
      <xsl:call-template name="FirstNWords">
        <xsl:with-param name="TextData" select="substring-after($TextData, ' ')"/>
        <xsl:with-param name="WordCount" select="$WordCount - 1"/>
        <xsl:with-param name="MoreText" select="$MoreText"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="(string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, '  ')) &gt; 0)">
      <xsl:value-of select="concat(substring-before($TextData, ' '), $MoreText)" disable-output-escaping="yes"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$TextData" disable-output-escaping="yes"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<!-- Begin NewsCategory Template -->
<xsl:template name="NewsCategory" match="Row[@Style='NewsCategory']" 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="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="Created">
		<xsl:value-of select="ddwrt:FormatDateTime(string(@ArticleStartDate) ,1033 ,'dd MMMM')" />
	</xsl:variable>
	<xsl:variable name="LinkTarget">
		<xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
	</xsl:variable>
<!-- First row -->
<xsl:variable name="CurPosition" select="count(./preceding-sibling::*)" />
<xsl:if test="count(preceding-sibling::*)=0"> 
<ul class="CQWP-Header tabs">	
	<li id="NewsLink1"><a href="#">Internal</a></li>
	<li id="NewsLink2"><a href="#">External</a></li>
</ul>
</xsl:if>
<!-- Internal -->
<xsl:if test="@NewsCategory = 'Internal'">
<div class="Internal CQWP-Content">
		<xsl:value-of select="$Created"/>
		<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}" >
			<xsl:call-template name="FirstNWords">
        		<xsl:with-param name="TextData" select="$DisplayTitle"/>
       			<xsl:with-param name="WordCount" select="7"/>
        		<xsl:with-param name="MoreText" select="'...'"/>
      		</xsl:call-template>
		</a>
</div> 
</xsl:if>
<!-- External -->
<xsl:if test="@NewsCategory = 'External'">
<div class="External CQWP-Content">
		<xsl:value-of select="$Created"/>
		<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}" >
			<xsl:call-template name="FirstNWords">
        		<xsl:with-param name="TextData" select="$DisplayTitle"/>
       			<xsl:with-param name="WordCount" select="7"/>
        		<xsl:with-param name="MoreText" select="'...'"/>
      		</xsl:call-template>
		</a>
</div> 
</xsl:if>
<!-- Last row -->
<xsl:if test="count(following-sibling::*)=0">
	<div class="CQWP-Footer">
		<div class="CQWP-Archive">
			<a href="#">More news »</a>
		</div>
	</div>
</xsl:if>
</xsl:template>

Stay tune for part III and please drop a comment if you got any questions, Christian

Display News pages with CQWP – Part I — May 28, 2011

Display News pages with CQWP – Part I

One of my favorite web parts in SharePoint Server is the Content By Query Web Part (CQWP), that let us display a dynamic view of aggregate content in the site collection and present this in a web part. We can set a query that determines what content that should be displayed, and how the content presents. A common example where the CQWP is useful is when you need to display the latest 5 news at the start page.

However, sometimes you may need to modify how the data renders and create a design that ties with graphic profile. To achieve this you can use XSLT, CSS, CAML and jQuery or even write your own markup in HTML.

This article will not cover how to configure the CQWP or to modify ItemStyle.xsl or the other XSL files that describes the CQWP, we´re going straight to the core to the templates in the ItemStyle.xsl and to the CSS classes.
More about the CQWP at MSDN:
Common SharePoint Web Part and Field Control Customization Tasks

In the next article (Part II) II’l write about how to extend this format with jQuery.

Things we need to do with the XSLT in ItemStyle and with CSS to create format as the image above:

  • Display the created date and the month abbreviated
  • Count words, the title should be displayed by a max number of words and not be cut off in the middle. If the title is longer than 7 words, three dots should be displayed afterwards.
  • Header and footer, Latest news and More news
  • Design in general including an alternate background color for odd and even rows

Created date

Add the following namespace attribute to the root xsl:stylesheet element in ItemStyle:

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

Create an xsl:variable element:

<xsl:variable name="Created"><xsl:value-of select="ddwrt:FormatDateTime(string(@ArticleStartDate) ,1033 ,'d MMMM')" />
</xsl:variable>

Use the variable:

<xsl:value-of select="$Created"/>

In this example I used a custom column called ArticleStartDate, you can just use @Created if you like. For more info about custom date and time format string, read more at MSDN

Count words

The title should be displayed by max 7 words and not be cut off in the middle and if the title is longer than 7 words, three dots should be displayed afterwards. To do this we need a ‘FirstNwords’ template, and such a template among more useful templates can be found at Codeplex.

Read more about this at Marc D Andersons blog:
Displaying the first n words of a long text column with xsl’ and check out
SPXSLT, a collection of useful XSL templates at Codeplex.

Header & Footer; First and Last row

Create a variable that gives the rows position

<xsl:variable name="CurPosition" select="count(./preceding-sibling::*)" />

Use preceding to get the first row

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

Use following to get the last row

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

Alternate background

First you have to create a variable that gives the rows position, just like for the header and rows. No need to do this twice, secondly create a variable in order to get odd or even rows so you can set CSS classes depending if it´s odd or even rows.

<xsl:variable name="OddOrEven" >
<xsl:choose>     
<xsl:when test="($CurPosition mod 2 = 0)">        
<xsl:text>CQWP-Odd</xsl:text>     
</xsl:when>
<xsl:otherwise>
<xsl:text>CQWP-Even</xsl:text>
</xsl:otherwise>     
</xsl:choose>
</xsl:variable>

That´s all, time to try this out:

Two complete templates

The word counter template:

<!-- Word counter Template -->
<xsl:template name="FirstNWords">
  <xsl:param name="TextData"/>
  <xsl:param name="WordCount"/>
  <xsl:param name="MoreText"/>
  <xsl:choose>
    <xsl:when test="$WordCount &gt; 1 and (string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, '  ')) &gt; 0)">
      <xsl:value-of select="concat(substring-before($TextData, ' '), ' ')" disable-output-escaping="yes"/>
      <xsl:call-template name="FirstNWords">
        <xsl:with-param name="TextData" select="substring-after($TextData, ' ')"/>
        <xsl:with-param name="WordCount" select="$WordCount - 1"/>
        <xsl:with-param name="MoreText" select="$MoreText"/>
      </xsl:call-template>
    </xsl:when>
    <xsl:when test="(string-length(substring-before($TextData, ' ')) &gt; 0 or string-length(substring-before($TextData, '  ')) &gt; 0)">
      <xsl:value-of select="concat(substring-before($TextData, ' '), $MoreText)" disable-output-escaping="yes"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$TextData" disable-output-escaping="yes"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The OddEven template:

<!-- Begin OddEven Template -->
<xsl:template name="OddEven" match="Row[@Style='OddEven']" 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="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="Created">
		<xsl:value-of select="ddwrt:FormatDateTime(string(@ArticleStartDate) ,1033 ,'d MMMM')" />
	</xsl:variable>
	<xsl:variable name="LinkTarget">
		<xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
	</xsl:variable>
 
<!-- First row -->
<xsl:variable name="CurPosition" select="count(./preceding-sibling::*)" />
<xsl:if test="count(preceding-sibling::*)=0"> 
<div class="CQWP-Header">Latest news</div>
</xsl:if>

<!-- Create var for alternate classes -->
<xsl:variable name="OddOrEven" >
	<xsl:choose>     
		<xsl:when test="($CurPosition mod 2 = 0)">        
			<xsl:text>CQWP-Odd</xsl:text>     
		</xsl:when>
		<xsl:otherwise>
			<xsl:text>CQWP-Even</xsl:text>
		</xsl:otherwise>     
	</xsl:choose>
</xsl:variable>

<!-- All rows between the first and the last -->
<div id="linkitem" class="{$OddOrEven}">
	<xsl:value-of select="$Created"/>
	
		<a href="{$SafeLinkUrl}" target="{$LinkTarget}" title="{@LinkToolTip}" >
			<xsl:call-template name="FirstNWords">
        		<xsl:with-param name="TextData" select="$DisplayTitle"/>
       			<xsl:with-param name="WordCount" select="7"/>
        		<xsl:with-param name="MoreText" select="'...'"/>
      		</xsl:call-template>
		</a>
</div>

<!-- Last row -->
<xsl:if test="count(following-sibling::*)=0">
	<div class="CQWP-Footer">
		<div class="CQWP-Archive">
			<a href="#">More news »</a>
		</div>
	</div>
</xsl:if>
</xsl:template>

Dont forget to add the following namespace attribute to the root xsl:stylesheet element in the head of the document, when use the ddwrt formating for the date.

Here is the CSS:

.CQWP-Header, .CQWP-Archive {
width:400px;
border-width:1px;
height:20px;
padding-top:5px;	
padding-bottom:0px;
color:#333;
font-family:Cambria, Georgia;
border-style:solid none none none;
border-width:1px;
border-color:#bdbdbd;   
}
.CQWP-Header{
font-size:12px; font-weight:bold;
padding-left:10px;
border-style:solid none dotted none;
border-color:#bdbdbd;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#e2e2e2', endColorstr='#ebebeb'); 
background: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#e2e2e2)); 
background: -moz-linear-gradient(top,  #ebebeb,  #e2e2e2);
}
.CQWP-Archive {
margin-top:-1px; font-size:11px;
padding-right:10px; text-align:right;
border-style:dotted none solid none;
border-color:#bdbdbd;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ebebeb', endColorstr='#e2e2e2'); 
background: -webkit-gradient(linear, left top, left bottom, from(#e2e2e2), to(#ebebeb));
background: -moz-linear-gradient(top,  #e2e2e2,  #ebebeb);
}
.CQWP-Odd, .CQWP-Even {
border-style:none none solid none;
border-width:1px; border-color:#e5e5e5;
height:22px; padding-top:7px;	
padding-bottom:0px; padding-left:10px;
color:#333; width:390px;
font-family:Cambria, Georgia; font-size:11px
}
.CQWP-Odd {background-color:#f7f7f7;}
.CQWP-Even {background-color:#fff;}
.CQWP-Odd a:link, .CQWP-Odd a:visited, .CQWP-Even a:link, .CQWP-Even a:visited {
padding-left:25px;color:green;
}

Stay in tune for the next article (Part II) about how to extend this format with jQuery. Thanks dropping by!