Customize the UI of web parts in SharePoint 2010
This post describes how to customize a standard Web Part in SharePoint by using SharePoint Designer 2010. Depending of the look and feel or factors such as accessibility, performance or cross browser stability it could be a challenge to bend the web part UI exactly in the way you want. The markup of the web parts in SharePoint contains a quite deep nested table structure and the elements do not always have an id or class.
When you need to create an advanced design for the web parts, the alternatives is to manipulate the DOM with jQuery or create custom web part control wrappers with code. Besides of this, CSS 3 comes with some interesting possibilities like box shadow and border radius that lets you create stuff like boxes with curved corners but it’s not an option here because we need to render the master page in IE8 mode to get all functionalities intact in SharePoint 2010.
So what can you do quick and easily then? The web part headers and all the cells in header row can easily be customized with CSS just like the borders around. I have made four examples with different colors you can download and use at the bottom of this page.
Using only CSS and images for rounded corners is the easiest approach where you don’t need plugins like CSS3 Pie or other htc solutions, fallback methods for different browsers or care about slow rendering when rewriting the already complex and nestled DOM. But when you reach the border of what is possible to do with just CSS and images it’s time to bend the DOM with our friend jQuery or fire up Visual Studio for write a control adapter. Take a look at this blog post from ‘All things SharePoint’ that describes how to use jQuery to adding classes and wrappers into the DOM so you can get a wrapper with rounded corners for the web parts, and take a look at Waldek Mastykars post about how to removing the web part tables with code.
Back to the basics, let’s see how you can customize the web part headers the easy way.
The following example, see the image above, applies background images for the corners and for the middle section. The left and right corners have dimensions of 7 x 33 pixels, and the middle image has dimensions of 14 x 33 pixels.
Let’s go
Download the images and put them into Style Library/BlogBranding/Images or change the path in the CSS below if you want to put the images in some other folder.
/* WebPart headers */
/* All tdS in the row */
.ms-WPHeader > TD{
background-image: url('/Style Library/BlogBranding/Images/WP-MidGreen.png');
background-repeat:repeat-x;
padding-left:1px; padding-right:1px; height:33px;
border-bottom-style:none!important;border-bottom-color:inherit!important; border-bottom-width:0px!important;
}
/* Left cell */
.ms-WPHeader td:first-child {
width:5px;
background-image:url('/Style Library/BlogBranding/Images/WP-LeftGreen.png')!important;
background-repeat:no-repeat;
}
/* Right cell */
.ms-wpTdSpace {
width:7px;
background-image:url('/Style Library/BlogBranding/Images/WP-RightGreen.png')!important;
background-repeat:no-repeat;
background-color:transparent;
}
/* Arrow */
.ms-WPHeaderTdMenu{
background-color:transparent;
border:0px!important;
}
/* Web part title */
.ms-WPTitle {
padding-left:10px;
font-family:Arial, Helvetica, sans-serif;
color:#fff;
font-weight:bold;
margin-bottom:1px;
font-size:14px;
}
/* linked title and visited */
.ms-WPTitle a, .ms-WPTitle a:visited {
color:#fff;
text-decoration:none;
}
/* hover title */
.ms-WPTitle a:hover {
color:#333;
text-decoration:none;
}
/* hover web part menu */
.ms-WPHeaderTdMenu:hover{
border-left:1px solid transparent;
background-image: url('/Style Library/BlogBranding/Images/WP-MidGreen.png');
}
More stuff you can do
If you want to do something special just for one single web part based on some condition or similar? Let’s say you want to have a different look and feel for some web part only if its header text is ‘Links’. I made up an example that makes the header title red and adds a border with a dropshadow filter older IEs and BoxShadow for modern browsers. Other web parts will not apply this look and feel.
Here’s the jQuery
$(document).ready(function() {
var WPtitle = $('.ms-WPTitle span');
for (var i = 0; i <= WPtitle.length; i++) {
if ($(WPtitle[i]).text() == 'Links') {
$(WPtitle[i]).css({'color': 'red'});
$(WPtitle[i]).parents().eq(10).addClass("WebPartBorder");
}
else if ($(WPtitle[i]).text() == 'Shared Documents') {
$(WPtitle[i]).css({'color': 'blue'});
}
}
});
Here’s the CSS
/* All TDs in the table row */
.ms-WPHeader TD{
background-color: #f7f7f7;
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);
border-top:1px #cfcfcf solid; border-bottom:1px #e2e2e2 solid!important;
padding:3px;
}
/* for css / jquery drop shadow */
.WebPartBorder{
border:1px #777 solid!important;
-moz-box-shadow: 5px 5px 5px #ccc;
-webkit-box-shadow: 5px 5px 5px #ccc;
box-shadow: 5px 5px 5px #ccc;/* CSS3 */
background-color:#fff;
filter: progid:DXImageTransform.Microsoft.DropShadow(OffX=5, OffY=5, Color=#e9e9e9);
}
.WebPartBorder > tbody {
background-color:#f7f7f7!important
}
/* Border to the sides */
.ms-WPHeader td:first-child {
border-left:1px #e2e2e2 solid;
border-right:0px;
}
.ms-wpTdSpace {
border-right:1px #e2e2e2 solid;
}
/* Web part title */
.ms-WPTitle {
color: #333;
font-weight:bold;
}
/* linked title and visited */
.ms-WPTitle a, .ms-WPTitle a:visited {
color: #333!important;
text-decoration:none!important;
}
/* hover title */
.ms-WPTitle a:hover {
color:#0072bc!important;
}
/* hover web part menu */
.ms-WPHeaderTdMenu:hover{
background-image:none;
border-top:1px solid #ccc;
border-right:1px solid transparent;
border-left:1px solid transparent;
background-color:#f7f7f7;
}
/* for the jQuery */
.LinkTextColor {
color:red;
}
Hopes this gives you some ideas, and please feel free to drop a comment!
/ Christian
Branding the Search box in SharePoint 2010
I have written some blog posts previously about branding the global navigation which is an important part of the SharePoint user interface. The search box is another part of the user interface that often needs a bit branding especially if it concerns a public faced web site where the search box could be one of the most important elements in the user interface.

Customization of the SharePoint search box could be a challenge, there´s a lot to keep in mind when it comes to position and behaviors but also when it comes to all functionalities this control offers. This example assumes that dropdown is not specified otherwise you have to add a couple of classes to brand the drop down as well.
I have also written an article at MSDN called ‘Creating a Design for SharePoint 2010 Global Navigation and Search Boxes’ where you will find some more examples of how to extend the search box with CSS and jQuery.
About the search box control
The search box control renders as a placeholder in the master page and can be replaced by a custom control that is inherited from the SharePoint SearchBoxEx class. The control is a configurable Web Part and, as such, can be used as an ASP.NET control. You can use each property of the Search Box Web Part as an attribute on the Search Box Web control. To specify a style for the search box, such as a background color, background images, width or a font color, use only CSS. That is, you don’t need to modify the master page or write a custom control to customize the look and feel for the search box in common sceneries.
As you may notice I used rounded borders with CSS3, this will not work in IE 9 and below if you render the master page with the compatibility X-UA Compatible IE 8 which you should do because if you set the compatibility to IE 9 you will have some issues with page loads and button click events related to some functions like the PeopleEditor field in SharePoint. The CSS3 classes works good in other browsers that ignores the compatible tag. If you need rounded corners for the search box input field you can use a background image or use a JS crossbrowser solution like curvycorners.net
I have placed the search box in the top row in my example, if you want it in the same row as the global navigation you can add a DIV as a wrapper to the control so you can control vertical horizontal aligns, so it fits in as you want in the navigation.

If you use this CSS in an non branded SharePoint site it will looks like the image below:
CSS
Add this CSS in your custom CSS file:
.s4-search {margin-right:8px}
.ms-sbtable-ex {margin-top:1px!important}
.s4-search INPUT.ms-sbplain {
background-color: #fff;
background-image:url('/Style Library/Labb/Images/smallSearchIcon.png');
background-repeat: no-repeat;
background-position:5px 5px;
padding: 4px 0px 4px 25px;
height:13px;
border:#efefef 1px solid;
border-top-left-radius:5px;
border-bottom-left-radius:5px;
color:#333; font-size:11px;
}
.s4-search .ms-sbgo a{
background-image:url('/Style Library/Labb/Images/searchBtn.png');
background-repeat: no-repeat;
display:block;
height:23px; width:50px;
margin-top:0px; margin-left:0px
}
.ms-sbscopes, .srch-gosearchimg{
display:none;
}
Images
Download the searchbutton and the search icon here
A quick tip
As you may noticed, the search box is not visible by design in SharePoint on settings pages. That’s because the delegated search box is wrapped by a content placeholder. If you want to expose the search box at the setting pages, remove the place holder wrapper, just the wrapper not the delegated control, and place this in a ASP Panel with the attribute visible set to false, you can place the ASP panel just above the ending form tag in your custom master page.
Before:
<asp:ContentPlaceHolder id="PlaceHolderSearchArea" runat="server"> <SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox" Version="4"/> </asp:ContentPlaceHolder>
After:
<asp:Panel visible="false" runat="server"> <asp:ContentPlaceHolder id="PlaceHolderSearchArea" runat="server" /> </asp:Panel>
/ Christian
SharePoint 2010 branding examples
A couple of weeks ago I had two sessions at SharePoint & Exchange forum 2011 about branding in SharePoint and Data Views in SharePoint Designer. SEF was as usual a great event with a lot of good speakers like Marc D Anderson, Penny Coventry, Todd Klindt, Dan Holme, CA Callahan, Göran Husman, Wictor Wilén and many more.
I talked about theoretical aspects of branding like importance, decision points, tools and how to plan for a branding in SharePoint in general in the branding session and I showed how to brand the SharePoint user interface piece by piece, not by how to make dramatic changes to the interface; more about where to start and which classes you can modify per element like:
- Header area, faded background and height
- Logo
- Breadcrumbs
- Social icons, smaller icons and the added title text with jQuery
- Global navigation with dropdown
- Searchbox, custom button, background color and jQuery for replace the default text
As promised during my session about branding, you’ll find all CSS and jQuery you’ll need to create a look and feel like the image above. Please feel free to use this in the way you want.
CSS
Download all the CSS here
Changes in the master page
If you want to display one more level in the fly out for the global navigation
<!-- Global Navigation activate dropdown --> <SharePoint:AspMenu ID="TopNavigationMenuV4" Runat="server" EnableViewState="false" DataSourceID="topSiteMap" AccessKey="<%$Resources:wss,navigation_accesskey%>" UseSimpleRendering="true" UseSeparateCss="false" Orientation="Horizontal" StaticDisplayLevels="2" MaximumDynamicDisplayLevels="2" SkipLinkText="" CssClass="s4-tn"/>
In this example I used small icons for the social icons, to do this just add –mini to the Control Id
<!-- Mini Social Icons --> <SharePoint:DelegateControl ControlId="GlobalSiteLink3-mini" Scope="Farm" runat="server"/>
The mini extensions means that no text will be displayed, just the icon will show up. I used jQuery to set a custom attribute per icon with first and last child. Paste this jQuery in your custom Master page and don’t forget to add a reference to latest jQuery in the head section of the MasterPage.
<script type="text/javascript">
$(document).ready(function() {
$(".ms-mini-socialNotif-Container > a:first-child > span > span > IMG").attr({
title: "I like",
});
$(".ms-mini-socialNotif-Container > a:last-child > span > span > IMG").attr({
title: "Tags & note",
});
});
</script>
The searchbox button is an image in the dimensions of 37 x 25 px, create you own button or use a background color. I have tested this stuff in latest Firefox, GC and IE 9 and hopes this can give you some ideas and thanks so much to everyone that attended at my sessions, if you have any questions about my presentations, please feel free to contact me.
/ Christian
The Breadcrumb in SharePoint 2010
The breadcrumb in SharePoint is useful just like the other navigation elements like the global navigation. In SharePoint 2010 we have the PopoutMenu control which can be visible if you click at the folder icon in the ribbon. That’s cool, but if you want to display the breadcrumb as a part of every pages without the need to activate it, it just to add a ASP:SiteMapPath control onto your custom masterpage.
SiteMap
There’s no limit when it comes to style the breadcrumb, you can have a custom background and an image that separates the nodes if you like to. In my example I have placed the following code just above the ContentPlaceHolder ‘PlaceHolderMain’ tag in my custom masterpage.
<div class="BreadCrumbWrap s4-notdlg"> <asp:SiteMapPath runat="server" SiteMapProvider="SPContentMapProvider" id="ContentMap" CssClass="BreadCrumbStyle" PathSeparator=">"> <CurrentNodeStyle CssClass="BreadCurrentNode" /> <PathSeparatorStyle CssClass="BreadPathSeparator" /> </asp:SiteMapPath> </div>
Add the following CSS classes to your custom CSS file, referenced from the custom masterpage.
CSS
.BreadCrumbWrap {
margin-top:10px;
}
.BreadCrumbStyle {
padding-left:15px;
font-size:10px;border-bottom:1px #ebebeb dotted;
padding-bottom:5px;
}
.BreadCrumbStyle a:link, .BreadCrumbStyle a:visited {
color:#3b4f65;
}
.BreadCrumbStyle a:hover{
color:#0072bc; text-decoration:underline
}
.BreadCurrentNode {color:#0072bc}
.BreadPathSeparator{
color:#ccc; padding:0px 8px 0px 8px;
}
/ Christian
How to customize a grouped view in the Data View web part
How about to use a Data View Web Part (DWWP) to display a grouped view of news pages by year and month? Let’s improve the findability and give the users a simply way to browse the news pages in a news archive page. This technique could be useful for any kind of item in a list; you could for example do the same to display documents from a library or items in an announcement list.
Some things we need to do:
- Create two calculate columns that will serve us when the items is created or published; this is an easy way to create the grouping.
- Create a click function (expand / collapse) for the whole row, for the year and month in the group header.
- Show number of items for each month
- Sort the month by their actual numbers but display the month by their names
Let’s start!
- Open and the site that containing the news pages with SharePoint Designer 2010, in the example it’s a news site based on the publishing site template in SharePoint 2010 server.
- Add two new calculated columns to the Pages library. You can do this in SharePoint Designer or by the browser. Name the first column to ArticleYear with data type Single line of text. Us the formula: =TEXT([Article Date],”YYYY”) name the next column ArticleMonth with data type Single line of text. Us the formula: =TEXT([Article Date],”MM”). In this example I use a column called Article Date and I use this column in the actual page layout for the news pages. Be sure to include this column in your page layout and set dates to the news pages in the library. If you don’t want to use this column you can use the inbuilt column Created instead.
- Create a new aspx page with SharePoint Designer and open this page, save this somewhere in the site. Place the cursor inside the form tag and click Insert in the ribbon. Click at Display Item Form button and select Pages.
-
Before you’ll get into the code view, do the settings for the DVWP you’ll need with help of the ribbon buttons. Set the paging, filter, sort and grouping like this:
- Paging eq display All Items
- Add / Remove columns. Display this columns: Title, Article date, ArticleYear and ArticleMonth
- Filter eq article date Not Null
- Sort order eq Article Date desc
- Group ArticleYear by asc, show group header and make it collapse
- Group ArticleMonth by asc, show group header and make it collapse
At this point you’ll have the basic stuff needed to get going with the UI customizations. Now you it’s your turn to do the branding and start work on functionality. If you want to see my specific example, you can download the aspx page, the CSS and the image (see the bottom of this blog post) where you’ll see the HTML structure, how to set onclick at rows, how you todisplay month names how to count a nodeset to display numer of news items per each month. In this page you’ll also how you can display month names. When you done, you can save the web part as to a file and upload this to the news site and put in a news archive page.
A quick view of things you can do more
Display month names
<xsl:choose> <xsl:when test="$fieldvalue='01'">January</xsl:when> --- <xsl:when test="$fieldvalue='12'">December</xsl:when> <xsl:otherwise></xsl:otherwise> </xsl:choose>
Get number of items (news) per each month:
<xsl:value-of select="count($nodeset)"/>
Onclick event for the rows
<tr class="YearRow" id="group{$groupid}" style="display:{$displaystyle}" onclick="javascript:ExpGroupBy(this);return false;">
If you consider to use divs instead of tables, keep in mind that the ExpGroupBy function that lives in the Core.js needs to be overridden to match you structure.
One thing more, if you like to have this grouped DVWP connected to a a list instead of a Page library, no problems! The only thing that will be different is the link to the actual item, try rewrite the link like this:
<a href="{@FileDirRef}/DispForm.aspx?ID={@ID}"><xsl:value-of select="@Title" /></a>
/ Christian
Book review: SharePoint 2010 Branding in Practice
This book is for the web developer or designers that works and are quite familiar with branding in general and knows relevant techniques like CSS, HTML and JS and wants to know more about SharePoint 2010 branding; like approaches and best practices. You will find clear examples and advices to typical branding scenarios and it includes the code you’ll need related to the examples.
Hot spots from the book:
- How to set up a visual studio solution structure for branding
- Using module and provisioning techniques
- Branding publishing sites v/s collaboration sites
- Feature stapling for My site
- Customizing search center
- Branding list views
- Client side interaction with web services
- Third party UI components integration
- A lot of code with step to step instructions
SharePoint 2010 Branding in Practice is probably not your first choice if you’re more into the visual graphic design part of web designing, it’s aimed to the front end web developer or the web designer that implement mockups in SharePoint. If you want to learn development techniques and effective approaches when it comes to packing and deploying files and code applied to SharePoint Branding, this is definitive a straight forward book for you.
I like this book and can highly recommend it; if you want to break in more to SharePoint branding and need structured examples and best practices you will find a lot of great stuff that takes you to the next level in the air of SharePoint designing. Thanks for writing this book!
For source code or more information about the author, Yaroslav Pentsarskyy: www.sharemuch.com
Happy branding!
Christian
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="_blank"')" />
<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&web=',$WebUrl,'&page=',$PageId,'&wp=',$WebPartId,'&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('<div class="slideshow" style="width:')" />
<xsl:variable name="BeginColumn2" select="string('%" >')" />
<xsl:variable name="BeginColumn" select="concat($BeginColumn1, $cbq_columnwidth, $BeginColumn2)" />
<!--End Div - No end UL-->
<xsl:variable name="EndColumn" select="string('</div>')" />
<xsl:for-each select="$Rows">
<xsl:variable name="CurPosition" select="position()" />
<xsl:if test="($CurPosition >= $FirstRow and $CurPosition <= $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&Action=dispform&ItemId=',@ID,'&ListId=',@ListId,'&WebId=',@WebId,'&SiteId=',$SiteId,'&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"><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" > <xsl:import href="/Style Library/XSL Style Sheets/Header.xsl" /> <xsl:import href="/Style Library/XSL Style Sheets/ItemStyleImageCycle.xsl" /> <xsl:import href="/Style Library/XSL Style Sheets/ContentQueryMainImageCycle.xsl" /> </xsl:stylesheet></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
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 > 1 and (string-length(substring-before($TextData, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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” 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
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
Le’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 > 1 and (string-length(substring-before($TextData, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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
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 > 1 and (string-length(substring-before($TextData, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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, ' ')) > 0 or string-length(substring-before($TextData, ' ')) > 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!





