Second Life of a Hungarian SharePoint Geek

July 23, 2013

Creating a Flash Video Player For SharePoint using the built-in web parts – Version 2

Filed under: CQWP, jQuery, SP 2010 — Tags: , , — Peter Holpar @ 22:51

In my recent post I illustrated how to query a Flash (FLV) video player web part using the built-in Content Editor Web Part (CEWP) and some JavaScript. In the current post I will show you how to achieve the same with Content Query Web Part (CQWP) by altering the standard ItemStyle.xsl and the ContentQueryMain.xsl files.

For the prerequisites regarding the document library for the Flash files, Flowplayer and jQuery libraries read the previous post.

If you don’t have experience in customizing XSL style sheet files, I recommend you to read the following articles first:

How to: Customize XSL for the Content Query Web Part

Customizing the Content Query Web Part and Custom Item Styles

To be sure that our customizations do not interfere with any other web part, we do not edit the original XSL files. Instead, open your site with SharePoint Designer 2010, locate the XSL files above and create a copy of them for editing. I created a new folder called Custom in Style Library/XSL Style Sheets, and copied both files there.

image

First, open the ContentQueryMain.xsl file for editing. We need to have a video player object at the top of the web part if our custom item style VideoList is selected in the CQWP. To achieve this goal, we have to edit the OuterTemplate.Body template, however, in this case we face with a problem. The selected item style is not available in the OuterTemplate.Body template out of the box as a parameter. As a workaround, we should read the Style attribute of the first item in Rows. The remaining of the customizations is pretty simple.

Locate the OuterTemplate.Body template in the ContentQueryMain.xsl, and insert the code below after the declaration of the EndColumn variable.

Code Snippet
  1. <xsl:variable name="Style" select="$Rows[1]/@Style" />
  2. <xsl:choose>
  3.     <xsl:when test="$Style='VideoList'">
  4.         <xsl:text disable-output-escaping="yes">
  5.             <![CDATA[
  6. <script type="text/javascript" src="/_layouts/flowplayer/flowplayer-3.2.12.min.js"></script>
  7. <script type="text/javascript" src="/_layouts/jQuery/jquery-1.8.3.min.js"></script>
  8. <link rel="stylesheet" type="text/css" href="/_layouts/flowplayer/style.css"></link>
  9. <span><a style="display:block;width:520px;height:330px" class="VideoPlayer"></a></span>
  10. <script language="ecmascript" type="text/ecmascript">
  11.     function startClip(src, title) {
  12.       flowplayer().play([{url: src, title: title}]);
  13.     }
  14.     
  15.     $(document).ready(startScript);
  16.     
  17.     function startScript() {
  18.       flowplayer("a.VideoPlayer", "/_layouts/flowplayer/flowplayer-3.2.16.swf");
  19.     }
  20. </script>
  21. ]]>
  22.         </xsl:text>
  23.     </xsl:when>
  24. </xsl:choose>

Next, open ItemStyle.xsl and insert the code below as the last template:

Code Snippet
  1. <xsl:template name="VideoList" match="Row[@Style='VideoList']" mode="itemstyle">
  2.     <xsl:variable name="SafeLinkUrl">
  3.         <xsl:call-template name="OuterTemplate.GetSafeLink">
  4.             <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  5.         </xsl:call-template>
  6.     </xsl:variable>
  7.     <xsl:variable name="DisplayTitle">
  8.         <xsl:call-template name="OuterTemplate.GetTitle">
  9.             <xsl:with-param name="Title" select="@Title"/>
  10.             <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  11.         </xsl:call-template>
  12.     </xsl:variable>
  13.     <div class="item link-item" style="text-align:left;">
  14.         <a href="javascript:void(0)" title="{$DisplayTitle}" onclick="startClip('{$SafeLinkUrl}', '')">
  15.             <xsl:value-of select="$DisplayTitle"/>
  16.         </a>
  17.     </div>
  18. </xsl:template>

Save the changes in both files and publish a new version of them. Run IISRESET.

Add a new CQWP to your page, and set the properties according to the figures below. VideoLib1 is the document library that contains my Flash movies, you should select your own library there:

image

image

Export the web part, open it using a text editor, and alter the ItemXslLink, MainXslLink and Xsl properties to refer to the customized ItemStyle.xsl and the ContentQueryMain.xsl files. Delete the original web part from the page and import the altered one.

The outcome of the web part is very similar to the CEWP version in my previous post.

image

There is however a significant benefit of using a CQWP rather than a CEWP: in the first case you can easily configure your web part to query not only a single document library, but a whole web site (including subsites) or even a whole site collection for Flash movies. If you like, you can even configure the CQWP to group movie files by their location, like the name of the document library.

March 17, 2011

Displaying results in multiple columns using the Content Query Web Part – the other direction

Filed under: CQWP, SP 2010 — Tags: , — Peter Holpar @ 09:37

I posted a solution for something similar more than a year ago, but a commenter asked me if it is possible (and how) to do the same in the opposite direction.

For example, assuming eight articles and a two-column display, in the original post the articles were ordered like this:

1 2
3 4
5 6
7 8

Instead of this, we should now have the following result:

1 5
2 6
3 7
4 8

Let’s see, what makes it a bit harder than the first approach. In HTML, the tables are build row-by-row, that is the first row is populated first with cells, then starts the second row, etc. until there is no more item and rendering finished at the last cell. That is very practical and easy to implement in the case of a Content by Query Web Part since it processes items in the order returned by the query.

(Side note: if it was not HTML, but WPF / Silverlight we could position items into arbitrary grid cell, that would make things much more easier. I’m not yet very familiar with HTML5, but I assume it should provide more flexibility for this kind of positioning as well. Comments are welcome to confirm or refute this assumption.)

Putting items in the same row into the same table row either has the definite advantage that it guarantees the height of the cells will be identical. When processing the items column-by-column you lose this possibility. You have to separate items some other way (for example breaks instead of table rows) that makes height synchronization rather hard. Either you should have items with the same original height or wrap your items into a container (like a div) that guarantees the identical height through its properties.

In this solution there is no difference in preparation of the ContentQueryMain.xsl file related to the original version. Please, see the description of the changes there.

The customization of the ItemStyle.xsl required a bit more speculation than expected, but after all that was not a rocket science either.

First, we set the column number as an XSLT variable again:

<xsl:variable name="ColNum" select="3" />

Columns may contain the same number of the items (rows) or there might be columns that contain more items than the others depending whether the overall item number can be divided by the column number without remainder. In this latter case these columns are the first ones (from the left), and they contains exactly one extra item. The number of columns with this extra item equals the modulo of the above-mentioned division.

Turning this theory into code results the following:

  1. <xsl:variable name="ModNum" select="$LastRow mod $ColNum" />
  2. <xsl:variable name="RowNumBase" select="($LastRow – $ModNum) div $ColNum" />
  3.  
  4. <xsl:variable name="RowNum">
  5.     <xsl:choose>
  6.         <xsl:when test="$CurPos &lt;= ($RowNumBase + 1) * $ModNum">
  7.             <xsl:value-of select="$RowNumBase + 1" />
  8.         </xsl:when>
  9.         <xsl:otherwise>
  10.             <xsl:value-of select="$RowNumBase" />
  11.         </xsl:otherwise>
  12.     </xsl:choose>
  13. </xsl:variable>

To be able to find the correct column endings, after processing the columns with the extra items we have to update the value of the current position counter to remove the extra items from the count:

  1. <xsl:variable name="CurPosUpd">
  2.     <xsl:choose>
  3.         <xsl:when test="$CurPos &lt;= ($RowNumBase + 1) * $ModNum">
  4.             <xsl:value-of select="$CurPos" />
  5.         </xsl:when>
  6.         <xsl:otherwise>
  7.             <xsl:value-of select="$CurPos – $ModNum" />
  8.         </xsl:otherwise>
  9.     </xsl:choose>
  10. </xsl:variable>

There are special formatting instructions before the first item,

  1. <xsl:if test="$CurPos = 1">
  2.     <xsl:text disable-output-escaping="yes">&lt;div&gt;&lt;table&gt;&lt;tr&gt;&lt;td width=&quot;</xsl:text><xsl:value-of select="round(100 div $ColNum)" /><xsl:text disable-output-escaping="yes">%&quot; valign=&quot;top&quot;&gt;</xsl:text>
  3. </xsl:if>

after the last item,

  1. <xsl:if test="$CurPos = $LastRow">
  2.     <xsl:text disable-output-escaping="yes">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;</xsl:text>
  3. </xsl:if>

and after the last items of each columns (except the overall last item):

  1. <xsl:if test="($CurPosUpd mod $RowNum = 0) and ($CurPos != $LastRow)">
  2.     <xsl:text disable-output-escaping="yes">&lt;/td&gt;&lt;td width=&quot;</xsl:text><xsl:value-of select="round(100 div $ColNum)" /><xsl:text disable-output-escaping="yes">%&quot; valign=&quot;top&quot;&gt;</xsl:text>
  3. </xsl:if>

Here is the complete XSLT source of our new News template:

  1. <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">
  2. <xsl:param name="CurPos" />
  3. <xsl:param name="LastRow" />
  4. <xsl:variable name="SafeLinkUrl">
  5.    <xsl:call-template name="OuterTemplate.GetSafeLink">
  6.      <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  7.    </xsl:call-template>
  8. </xsl:variable>
  9. <xsl:variable name="SafeImageUrl">
  10.     <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
  11.       <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
  12.     </xsl:call-template>
  13.   </xsl:variable>
  14.   <xsl:variable name="DisplayTitle">
  15.     <xsl:call-template name="OuterTemplate.GetTitle">
  16.       <xsl:with-param name="Title" select="@Title"/>
  17.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  18.     </xsl:call-template>
  19.   </xsl:variable>
  20.   <xsl:variable name="LinkTarget">
  21.     <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
  22.   </xsl:variable>
  23.   
  24.   <xsl:variable name="ColNum" select="3" />
  25.   <xsl:variable name="ModNum" select="$LastRow mod $ColNum" />
  26.   <xsl:variable name="RowNumBase" select="($LastRow – $ModNum) div $ColNum" />
  27.       
  28.   <xsl:variable name="RowNum">
  29.     <xsl:choose>
  30.       <xsl:when test="$CurPos &lt;= ($RowNumBase + 1) * $ModNum">
  31.           <xsl:value-of select="$RowNumBase + 1" />
  32.       </xsl:when>
  33.       <xsl:otherwise>
  34.         <xsl:value-of select="$RowNumBase" />
  35.       </xsl:otherwise>
  36.     </xsl:choose>
  37.   </xsl:variable>
  38.   
  39.   <xsl:variable name="CurPosUpd">
  40.     <xsl:choose>
  41.       <xsl:when test="$CurPos &lt;= ($RowNumBase + 1) * $ModNum">
  42.           <xsl:value-of select="$CurPos" />
  43.       </xsl:when>
  44.       <xsl:otherwise>
  45.         <xsl:value-of select="$CurPos – $ModNum" />
  46.       </xsl:otherwise>
  47.     </xsl:choose>
  48.   </xsl:variable>
  49.  
  50.  
  51.   <xsl:if test="$CurPos = 1">
  52.     <xsl:text disable-output-escaping="yes">&lt;div&gt;&lt;table&gt;&lt;tr&gt;&lt;td width=&quot;</xsl:text><xsl:value-of select="round(100 div $ColNum)" /><xsl:text disable-output-escaping="yes">%&quot; valign=&quot;top&quot;&gt;</xsl:text>
  53.   </xsl:if>
  54.     <table width="90%">
  55.       <tr height="27px" valign="top">
  56.         <td>
  57.           <span>
  58.             <a href="{$SafeLinkUrl}">
  59.               <xsl:value-of select="@Title"/>
  60.             </a>
  61.           </span>
  62.           <br />
  63.           <span>
  64.              <xsl:value-of select="ddwrt:FormatDateTime(@ArticleStartDate, 1033, 'MM-dd-yyyy')"/>
  65.           </span>
  66.         </td>
  67.       </tr>
  68.       <tr height="35px" min-height="35px" valign="top">
  69.         <td>
  70.           <span>
  71.             <xsl:if test="string-length($SafeImageUrl) != 0">
  72.               <div class="image-area-left">
  73.                 <a href="{$SafeLinkUrl}" target="{$LinkTarget}">
  74.                   <img class="image" width="100px" height="100px" src="{$SafeImageUrl}" alt="{@ImageUrlAltText}" />
  75.                 </a>
  76.               </div>
  77.             </xsl:if>
  78.             <xsl:value-of select="substring(@Comments,0,200)"/>
  79.             <xsl:if test="string-length(@Comments) &gt; 200">…</xsl:if>
  80.           </span>
  81.           <a href="{$SafeLinkUrl}"> Details…</a>
  82.         </td>
  83.       </tr>
  84.     </table>
  85.  
  86.   <xsl:if test="($CurPosUpd mod $RowNum = 0) and ($CurPos != $LastRow)">
  87.     <xsl:text disable-output-escaping="yes">&lt;/td&gt;&lt;td width=&quot;</xsl:text><xsl:value-of select="round(100 div $ColNum)" /><xsl:text disable-output-escaping="yes">%&quot; valign=&quot;top&quot;&gt;</xsl:text>
  88.   </xsl:if>
  89.  
  90.   <xsl:if test="$CurPos = $LastRow">
  91.     <xsl:text disable-output-escaping="yes">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;</xsl:text>
  92.   </xsl:if>
  93.   
  94.   </xsl:template>

Don’t forget to add the ddwrt namespace to the stylesheet to enable date formatting.

xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime&quot;

I’ve added Comments and ArticleStartDate fields to the view fields:

<property name="CommonViewFields" type="string">Comments,Note;ArticleStartDate,DateTime</property>

BTW, SharePoint 2010 makes that easier for you, see the settings of CQWP:

image

I’ve set the items to be ordered by the Article Date field,

image

and the CQWP to apply the News item style.

image

Finally, these are the results of the rendering for different column number values specified in the ColNum variable:

For value 1 (that I assume no worth after all of these above):

image

For value 2:

image

For value 3:

image

For value 4:

image

For value 5:

image

January 21, 2010

Displaying results in multiple columns using the Content Query Web Part

Filed under: CQWP, SharePoint — Tags: , — Peter Holpar @ 10:14

It’s a rather common request to display CQWP results in multiple columns. In this post I will show you how to do that by altering the ItemStyle.xsl and the ContentQueryMain.xsl files. Check out and open both of these files in Style Library / XSL Style Sheets folder using SharePoint Designer 2007.

If you don’t have experience in customizing XSL style sheet files, I recommend you to read the following articles first:

How to: Customize XSL for the Content Query Web Part

Customizing the Content Query Web Part and Custom Item Styles

The solution described here is only one of the possible solutions, you can achieve the same result applying different techniques.

First we edit the ContentQueryMain.xsl and add a new parameter LastRow in the call-template of the OuterTemplate.CallItemTemplate to pass the number of the last row at line 120 (assuming it is the original ContentQueryMain.xsl without customization).

Before modification:

  1. <xsl:call-template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:with-param name="CurPosition" select="$CurPosition" />
  3. </xsl:call-template>

After modification:

  1. <xsl:call-template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:with-param name="CurPosition" select="$CurPosition" />
  3.   <xsl:with-param name="LastRow" select="$LastRow" />
  4. </xsl:call-template>

We should also modify the OuterTemplate.CallItemTemplate template to be able to receive the new parameter value. We add the new  LastRow parameter at line 135.

Before modification:

  1. <xsl:template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:param name="CurPosition" />

After modification:

  1. <xsl:template name="OuterTemplate.CallItemTemplate">
  2.   <xsl:param name="CurPosition" />
  3.   <xsl:param name="LastRow" />

We have to pass the value of the LastRow parameter as well as the CurPosition parameter that is the number of the actual row to our item template. We will call our template News, and add the following block to the OuterTemplate.CallItemTemplate template just before the otherwise block at line position 152. Note that the value of the CurPosition parameter will be passed further in the CurPos parameter to fit to the existing naming conventions of the style XSL files.

  1. <xsl:when test="@Style='News'">
  2.   <xsl:apply-templates select="." mode="itemstyle">
  3.     <xsl:with-param name="CurPos" select="$CurPosition" />
  4.     <xsl:with-param name="LastRow" select="$LastRow" />
  5.   </xsl:apply-templates>
  6. </xsl:when>

After the preparation of the ContentQueryMain.xsl file, we should create the News item style itself in the ItemStyle.xsl. The following XML fragment illustrates a possible formatting. Of course, you are free to modify that, keeping the main points in your mind.

In the first example we create two columns. We use the values of CurPos parameter and the LastRow parameter to decide what special table formatting should be applied.

We create the table header for the first row, table footer for the last row, table row opening for odd rows and table row closing for even rows. We use the mod operator to check if an item represents an even or an odd row.

  1. <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">
  2.   <xsl:param name="CurPos" />
  3.   <xsl:param name="LastRow" />
  4.   <xsl:variable name="SafeLinkUrl">
  5.     <xsl:call-template name="OuterTemplate.GetSafeLink">
  6.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  7.     </xsl:call-template>
  8.   </xsl:variable>
  9.   <xsl:variable name="SafeImageUrl">
  10.     <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
  11.       <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
  12.     </xsl:call-template>
  13.   </xsl:variable>
  14.   <xsl:variable name="DisplayTitle">
  15.     <xsl:call-template name="OuterTemplate.GetTitle">
  16.       <xsl:with-param name="Title" select="@Title"/>
  17.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  18.     </xsl:call-template>
  19.   </xsl:variable>
  20.   <xsl:variable name="LinkTarget">
  21.     <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
  22.   </xsl:variable>
  23.  
  24.   <xsl:if test="$CurPos = 1 ">
  25.     <xsl:text disable-output-escaping="yes">&lt;div&gt;&lt;table&gt;</xsl:text>
  26.   </xsl:if>
  27.   <xsl:if test="$CurPos mod 2 = 1">
  28.     <xsl:text disable-output-escaping="yes">&lt;tr&gt;</xsl:text>
  29.   </xsl:if>
  30.  
  31.  
  32.   <td width="50%" valign="top">
  33.     <table width="90%">
  34.       <tr height="27px" valign="top">
  35.         <td>
  36.           <span>
  37.             <a href="{$SafeLinkUrl}">
  38.               <xsl:value-of select="@Title"/>
  39.             </a>
  40.           </span>
  41.           <span>
  42.              <xsl:value-of select="ddwrt:FormatDateTime(@ArticleStartDate, 1033, 'MM-dd-yyyy')"/>
  43.           </span>
  44.         </td>
  45.       </tr>
  46.       <tr height="35px" min-height="35px" valign="top">
  47.         <td>
  48.           <span>
  49.             <xsl:if test="string-length($SafeImageUrl) != 0">
  50.               <div class="image-area-left">
  51.                 <a href="{$SafeLinkUrl}" target="{$LinkTarget}">
  52.                   <img class="image" width="100px" height="100px" src="{$SafeImageUrl}" alt="{@ImageUrlAltText}" />
  53.                 </a>
  54.               </div>
  55.             </xsl:if>
  56.             <xsl:value-of select="substring(@Comments,0,200)"/>
  57.             <xsl:if test="string-length(@Comments) &gt; 200"></xsl:if>
  58.           </span>
  59.           <a href="{$SafeLinkUrl}"> Details…</a>
  60.         </td>
  61.       </tr>
  62.  
  63.     </table>
  64.   </td>
  65.  
  66.   <xsl:if test="$CurPos mod 2 = 0">
  67.     <xsl:text disable-output-escaping="yes">&lt;/tr&gt;</xsl:text>
  68.   </xsl:if>
  69.   <xsl:if test="$CurPos = $LastRow ">
  70.     <xsl:text disable-output-escaping="yes">&lt;/table&gt;&lt;/div&gt;</xsl:text>
  71.   </xsl:if>
  72. </xsl:template>

Note the text elements having disable-output-escaping="yes". We should use these elements since the XSL must be a well formed XML, so we cannot add unclosed or unopened HTML tags.

Don’t forget to add the ddwrt XML namespace to the stylesheet to enable date formatting and save both of the files.

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

If you don’t have content on your publishing site, create a few articles, and add a CQWP to one of your pages to aggregate the pages. You should also add the ArticleStartDate field to the CQWP CommonViewFields, to be sure it is included in the result:

<property name="CommonViewFields" type="string">ArticleStartDate,DateTime;</property>

If you don’t know how to do that, refer to this article:

How to: Customize the Content Query Web Part by using Custom Properties

Also, set the Item style of the CQWP to News.

image

After these modifications, you should see something like that:

image

If the result is matching your expectations, do not forget to check in the ItemStyle.xsl and the ContentQueryMain.xsl files and publish the page with the CQWP to make the changes visible to visitors.

Let’s improve our style a bit. If you need more columns, you can apply the same mod operator to get the information if a table row starting or row closing HTML tag must be added, just use the number of the columns instead of the constant 2 used in the sample above, and decrease the column with of 50% used to divide the full with into two, for example, you can use 33% for three columns.

But it would be better if you would not have to bother with the internals of the template, but use a constant variable in the XML.

For the sake of simplicity and to avoid mismatches I include the entire item style, although it does not differ significantly from the previous version.

  1. <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">
  2.   <xsl:param name="CurPos" />
  3.   <xsl:param name="LastRow" />
  4.   <xsl:variable name="SafeLinkUrl">
  5.     <xsl:call-template name="OuterTemplate.GetSafeLink">
  6.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  7.     </xsl:call-template>
  8.   </xsl:variable>
  9.   <xsl:variable name="SafeImageUrl">
  10.     <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
  11.       <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
  12.     </xsl:call-template>
  13.   </xsl:variable>
  14.   <xsl:variable name="DisplayTitle">
  15.     <xsl:call-template name="OuterTemplate.GetTitle">
  16.       <xsl:with-param name="Title" select="@Title"/>
  17.       <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
  18.     </xsl:call-template>
  19.   </xsl:variable>
  20.   <xsl:variable name="LinkTarget">
  21.     <xsl:if test="@OpenInNewWindow = 'True'" >_blank</xsl:if>
  22.   </xsl:variable>
  23.  
  24.   <xsl:variable name="ColNum">3</xsl:variable>
  25.  
  26.   <xsl:if test="$CurPos = 1 ">
  27.     <xsl:text disable-output-escaping="yes">&lt;div&gt;&lt;table&gt;</xsl:text>
  28.   </xsl:if>
  29.   <xsl:if test="$CurPos mod $ColNum = 1">
  30.     <xsl:text disable-output-escaping="yes">&lt;tr&gt;</xsl:text>
  31.   </xsl:if>
  32.  
  33.  
  34.   <td valign="top">
  35.     <xsl:attribute name="width">
  36.       <xsl:value-of select="round(100 div $ColNum) + '%'" />
  37.     </xsl:attribute>
  38.     <table width="90%">
  39.       <tr height="27px" valign="top">
  40.         <td>
  41.           <span>
  42.             <a href="{$SafeLinkUrl}">
  43.               <xsl:value-of select="@Title"/>
  44.             </a>
  45.           </span>
  46.           <span>
  47.              <xsl:value-of select="ddwrt:FormatDateTime(@ArticleStartDate, 1033, 'MM-dd-yyyy')"/>
  48.           </span>
  49.         </td>
  50.       </tr>
  51.       <tr height="35px" min-height="35px" valign="top">
  52.         <td>
  53.           <span>
  54.             <xsl:if test="string-length($SafeImageUrl) != 0">
  55.               <div class="image-area-left">
  56.                 <a href="{$SafeLinkUrl}" target="{$LinkTarget}">
  57.                   <img class="image" width="100px" height="100px" src="{$SafeImageUrl}" alt="{@ImageUrlAltText}" />
  58.                 </a>
  59.               </div>
  60.             </xsl:if>
  61.             <xsl:value-of select="substring(@Comments,0,200)"/>
  62.             <xsl:if test="string-length(@Comments) &gt; 200"></xsl:if>
  63.           </span>
  64.           <a href="{$SafeLinkUrl}"> Details…</a>
  65.         </td>
  66.       </tr>
  67.  
  68.     </table>
  69.   </td>
  70.  
  71.   <xsl:if test="$CurPos mod $ColNum = 0">
  72.     <xsl:text disable-output-escaping="yes">&lt;/tr&gt;</xsl:text>
  73.   </xsl:if>
  74.   <xsl:if test="$CurPos = $LastRow ">
  75.     <xsl:text disable-output-escaping="yes">&lt;/table&gt;&lt;/div&gt;</xsl:text>
  76.   </xsl:if>
  77. </xsl:template>

The main change is that we introduced a new variable called ColNum, and set its value to 3, just to alter the original two-column behavior. We use the value of this parameter when applying the mod operator, and instead of having a fixed with of the table cell we compute that using the formula round(100 div $ColNum) + ‘%’.

Let’s save the new version and see the result!

image

If we change the value of the ColNum parameter to 4, after saving the file we get the following result:

image

Well, of course, we could make it even better and have the value of the ColNum variable from a template parameter, but I let you to do that improvement alone if you really need that kind of flexibility.

Using the Content Query Web Part to provide an RSS feed on a publishing site

Filed under: CQWP, SharePoint — Tags: , — Peter Holpar @ 00:48

CQWP that is part of the publishing infrastructure feature in MOSS 2007 provides an excellent way of aggregating information on the site. This web part has the capability to yield its content as an RSS feed.

You can customize the visual styles of the items using the XSL files, but what happens if you don’t want to display the items on the web user interface at all, and need the RSS feed only?

In this case we can create a custom web part that is derived from the CQWP, and override the Render method to display a link to the RSS feed. The feed of the CQWP is provided by the feed.aspx and we should pass a few query string parameters to this page to specify exactly the CQWP that should be used when creating the feed. These parameters help to identify the web, the page and the web part itself.

The following code block illustrates a sample implementation of the web part.

  1. using System;
  2. using System.Web.UI;
  3. using System.Web.UI.WebControls.WebParts;
  4. using Microsoft.SharePoint;
  5. using Microsoft.SharePoint.WebControls;
  6. using Microsoft.SharePoint.WebPartPages;
  7. using Microsoft.SharePoint.Publishing.WebControls;
  8. using Microsoft.SharePoint.Utilities;
  9.  
  10. namespace RSSWebPart
  11. {
  12.     public class RSSWebPart : ContentByQueryWebPart
  13.     {
  14.         protected override void Render(HtmlTextWriter writer)
  15.         {
  16.             try
  17.             {
  18.                 // RSS feed must be enabled for the web part
  19.                 if (FeedEnabled)
  20.                 {
  21.                     SPWeb web = SPContext.Current.Web;
  22.                     SPFile file = SPContext.Current.File;
  23.                     writer.Write(@"<a href='/_layouts/feed.aspx?xsl=1&web={0}&page={1}&wp={2}' style=""padding:3px;margin:0;""><img src='/_layouts/images/rss.gif' border='0' alt=""RSS""  />",
  24.                         SPEncode.UrlEncode(web.ServerRelativeUrl), file.UniqueId, StorageKey);
  25.                     if (!String.IsNullOrEmpty(FeedTitle))
  26.                     {
  27.                         writer.Write(@"<span style=""padding:0;margin:0;vertical-align:top;""><b>{0}</b></span><br /></a>",
  28.                             SPEncode.HtmlEncode(FeedTitle));
  29.                     }
  30.                     if (!String.IsNullOrEmpty(FeedDescription))
  31.                     {
  32.                         writer.Write("{0}<br />", SPEncode.HtmlEncode(FeedDescription));
  33.                     }
  34.                 }
  35.             }
  36.  
  37.             catch (Exception ex)
  38.             {
  39.                 // log the error here
  40.             }
  41.         }
  42.     }
  43. }

After deploying the web part we add a new instance of it to a page, and set the feed properties in the CQWP settings as illustrated below.

image

We also set the chrome type to None.

image

The next figure shows the result of the process.

image

The RSS feed will be opened by clicking on the feed title or on the RSS icon.

If you need more information about configuring the RSS support for a CQWP you will find a useful article about that here.

January 20, 2010

Displaying a customizable message when Content Query Web Part returns no result

Filed under: CQWP, SharePoint — Tags: , — Peter Holpar @ 22:23

The default behavior of the CQWP is to show nothing in the display mode when there is no item matching the query. Sometimes it is adequate, but sometimes it would be better to show at least some kind of message to the visitors.

You can alter the OuterTemplate.Empty XSLT template in the ContentQueryMain.xsl file, as described in this post of Johnny Harbieh’s blog. It’s relatively easy and straightforward, requires no custom code and deployment of assemblies, can be done using a simple SharePoint Designer 2007.

This method has a drawback that it displays a fixed message for the visitors, no matter what item or grouping style the web part is configured to use. That could have been improved by adding XSLT conditions (using if or choose/when/otherwise) on the @Style or @GroupStyle attributes on the item, but it still does not allow the message to be set by users on the web part level.

If you really need this kind of flexibility, you should derive your own custom web part that is inherited from the CQWP, as show below.

  1. using System;
  2. using System.Text;
  3. using Microsoft.SharePoint.Publishing.WebControls;
  4. using System.Web.UI.WebControls.WebParts;
  5. using System.Web.UI;
  6. using System.Data;
  7.  
  8. public class ContentByQueryWebPartEx : ContentByQueryWebPart
  9. {
  10.     private String _emptyHtml = null;
  11.  
  12.     [Personalizable(), WebBrowsable(true), WebDisplayName("EmptyHtml"), WebDescription("EmptyHtml")]
  13.     public string EmptyHtml
  14.     {
  15.         get
  16.         {
  17.             return _emptyHtml;
  18.         }
  19.         set
  20.         {
  21.             _emptyHtml = value;
  22.         }
  23.     }
  24.  
  25.     protected override void Render(HtmlTextWriter writer)
  26.     {
  27.         if (((Data == null) || (Data.Rows == null) || (Data.Rows.Count == 0)) && (!String.IsNullOrEmpty(EmptyHtml)))
  28.         {
  29.  
  30.             // No matching items, render the configured text
  31.             writer.Write(EmptyHtml);
  32.         }
  33.         else
  34.         {
  35.             // Use the default Render method
  36.             base.Render(writer);
  37.         }
  38.     }
  39. }

After deploying this web part, you can use it as a replacement for the CQWP, and configure the HTML that should be displayed when there is no result for the query.

Theme: Shocking Blue Green. Get a free blog at WordPress.com

Follow

Get every new post delivered to your Inbox.

Join 53 other followers