Tag: sharepoint2010

Using the SharePoint image description field in the CQWP

The problem

I have a list with an Image column. When adding items to the list, you get the ability to type a description for the image. Seems like this would be used as “alt” descriptive text, right?

Image information in list

Well, let’s pull this field into a Content Query Web Part. I’ll use the default of “image on left” just to see what happens. In the Fields to display section, I put in my “Image” column name, as shown below. I’m hoping that the image will be displayed on the page, and that my image description will show up as “alt” or “title” attributes.

CQWP settings

But nothing shows up! When I view the HTML, there is no “alt” attribute, and the “title” attribute is blank.

No title

Let’s check out the XSL to see what’s going on. Opening SharePoint Designer, go to Style Library > XSL Style Sheets > ItemStyle.xsl. Look for

<xsl:template name="Default" ...>

(which should be near the top) to find the default style. Going down further in the code, you should then be able to locate the <img> tag, which looks like this:

<img src="{$SafeImageUrl}" title="{@ImageUrlAltText}">

For some reason, the @ImageUrlAltText just isn’t showing up. Rather than fight with SharePoint to figure out why, let’s create our own custom Item Style.

The Solution

The first step is to make a new item style. You may find it easiest to find the chunk of code that correlates with an existing item style that is close to what you already want to use. For example – if “Image on left” suits your purposes, copy the “Default” chunk of code (it’s around 65 lines), which begins and ends with:

<xsl:template name="Default" ...>
...
</xsl:template>

Or, if you want to use the “Clickable Image” style, then look for this:

<xsl:template name="ClickableImage" ...>
...
</xsl:template>

Copy that code and paste it to create a new section. Edit the opening xsl:template tag attributes to look like this:

<xsl:template name="YourCustomName" match="Row[@Style='YourCustomName']" mode="itemstyle">

There are probably some xsl:variable elements immediately underneath the xsl:template tag. Let’s make a new variable to hold our image descriptive text. Add this code:

<xsl:variable name="ImageAltText">
<xsl:value-of select="substring-after(@ImageUrlAltText, ', ')" />
</xsl:variable>

(Brief explanation: After some testing, I noticed that SharePoint holds the image URL and alt text in the same field, which looks something like this if you pull it out: “imageurl, This is the descriptive text here.” So I just select the substring after the comma to grab the alt text, and pull that into my new custom variable, “ImageAltText.”)

Now, look for that <img> tag, and change the code to look like this — basically, change the “@” symbol into the “$.”

<img src="{$SafeImageUrl}" title="{$ImageAltText}">

You can keep this as the “title” attribute, or change it to “alt,” depending on what you want.

<img src="{$SafeImageUrl}" alt="{$ImageAltText}">

Save ItemStyle.xsl and check it in. (You have check in ItemStyle.xsl or else the changes won’t show up.) In your CQWP, change the item style dropdown to your new custom style. If all has gone well, you should see your image pulled in with the proper image description as your title (or alt) text!

Themable custom master page in SharePoint 2010

Once you understand how theme colors work in SharePoint 2010, you’re on your way to creating your own themable (or “themeable”) master pages!

This article is not going to go through the details of making your own master page, as there are plenty of resources on creating custom master pages in SharePoint 2010. Instead, I’ll cover what you need to know to successfully create a themable master page.

I’m going to start with my own custom master page design – here’s what it looks like:

1. Ensure graphics can be recolored appropriately.

The top header area has a wrapper div with an orange background color (#ffbe18). Inside the wrapper div, my menu div uses a white background color, but I have a transparent background PNG called “navtab.png,” positioned on the right side of the div so that there is a curved tab effect.

When a new theme is applied, SharePoint’s theming engine can recolor everything. The wrapper div’s background color can change (orange to green), the menu div’s background color can change (white to beige), and the non-transparent pixels in the graphic are recolored from orange to green as well.

So – for any images that you want to use as part of your theme, you’ll want to make sure that recoloring them will work as you want. For example, you would not want to use an image such as the one shown below, because there are different hues in the same graphic, so recoloring would not produce the desired effect. (Keep reading below about how recoloring images works so that you know exactly what you can do!)

By the way – any graphics that you want to be recolored must be in PNG format.

2. Set up your CSS without shorthand notations for colors and backgrounds.

Instead of writing your CSS like this:

#cc-topmenu {
background: #fff url('navtab.png') no-repeat top right;
margin-right: 250px;
height: 30px;
padding-left: 10px;
}

Write your CSS so that the background properties are separated:

#cc-topmenu {
background-color: #fff;
background-image: url('navtab.png');
background-repeat: no-repeat;
background-position: top right;
margin-right: 250px;
height: 30px;
padding-left: 10px;
}

3. Add in theme tokens

Now, add in theme comments — that is, theme “tokens.” You can replace colors (font colors, background colors, border colors) with the ReplaceColor token.

/* [ReplaceColor(themeColor:"COLOR")] */

Color: Dark1, Dark2, Light1, Light2, Accent1, Accent2, Accent3, Accent4, Accent5, Accent6, Hyperlink, FollowedHyperlink. You can also append -Lightest, -Lighter, -Medium, -Darker, -Darkest to get the various shades of each color. (For example — Light1-Medium will give you the “medium” shade of your Light 1 color from your theme.)

You can get even more variations by using the themeShade (darkening) or themeTint (lightening) properties, if one of the previous “Lightest… Darkest” shortcut properties don’t work for you.

/* [ReplaceColor(themeColor:"COLOR", themeShade:"VALUE")] */
/* [ReplaceColor(themeColor:"COLOR", themeTint:"VALUE")] */

Value: Decimal value from 1.0 (no change from the color) to 0.0 (extremely dark or extremely light). See the diagram below for how themeTint and themeShade values affect the accent color, which is orange. (This may require some experimentation on your part to get the desired color!)

The RecolorImage token uses the same color options, but you can apply the color options in a few different ways:

  • Tinting: Change the hues of the graphic to your color – this is the default
    /* [RecolorImage(themeColor:"Accent1")] */

    or

    /* [RecolorImage(themeColor:"Accent1"),method:"Tinting"] */
  • Blending: Mix your color with the original hues of the graphic
    /* [RecolorImage(themeColor:"Accent1",method:"Blending")] */
  • Filling: Completely replace all non-transparent pixels with the color
    /* [RecolorImage(themeColor:"Accent1",method:"Filling")] */

You can also recolor just a portion of an image by specifying a rectangular area with the “includeRectangle” property. The x and y values determine the upper left point of the rectangle, and then you specify the width and height of the rectangle to recolor.

/* [RecolorImage(themeColor:"Accent1-Lighter",method:"Filling",includeRectangle:{x:0,y:0,width:100,height:30})] */

Note that if you refer to the image multiple times in the CSS, the last reference to the image is what it will look like. The theming engine only creates one recolored version of the image, so it will choose whichever definition overrides the others.

Here’s what my CSS looks like after adding in the theme tokens (I’ve stripped out my layout code so that you can just see the colors):

body #s4-ribbonrow { /* recoloring the ribbon, originally black */
/* [ReplaceColor(themeColor:"Dark1")] */background-color: #000;
}
#s4-workspace { /* recoloring the main background, originally grey */
/* [ReplaceColor(themeColor:"Light1-Lightest")] */background-color: #eeeeee;
}
#cc-wrapper {
margin: 0 20px; /* recoloring the content area, originally white */
/* [ReplaceColor(themeColor:"Light1")] */background-color: #ffffff;
}
#cc-header {  /* recoloring the header, originally orange */
/* [ReplaceColor(themeColor:"Accent1")] */background-color: #ffbe18;
}
#cc-topmenu { /* recoloring the menu, originally white, and recoloring the right curved tab graphic, originally orange */
/* [ReplaceColor(themeColor:"Light1")] */background-color: #fff;
/* [RecolorImage(themeColor:"Accent1")] */background-image: url('navtab.png');
background-repeat: no-repeat;
background-position: top right;
}
#cc-left { /* recoloring the gradient background image behind the left column, originally green */
/* [RecolorImage(themeColor:"Accent2-Lightest")] */background-image: url('leftbg.png');
}
.s4-ql ul.root > li > .menu-item, .s4-qlheader, .s4-qlheader:visited { /* recoloring the navigation headers */
/* [ReplaceColor(themeColor:"Accent2-Darker")] */color: #3e750e;
}
.s4-ql ul.root ul > li > a { /* recoloring the navigation links */
/* [ReplaceColor(themeColor:"Dark1")] */color: #000;
}
#cc-breadcrumbs { /* recoloring the breadcrumb navigation */
/* [ReplaceColor(themeColor:"Accent2")] */color: #82c942;
}
.ms-rteElement-H1B { /* recoloring the heading font */
/* [ReplaceColor(themeColor:"Accent1")] */color: #ffbe18;
}
.ms-rteElement-P { /* recoloring paragraph font */
/* [ReplaceColor(themeColor:"Dark1-Medium")] */color: #666;
}

Important note: Everything is case-sensitive!! So “Dark1-medium” won’t work. You MUST put “Dark1-Medium.”

4. Put your CSS in a Themable folder

Your CSS (and image) files should go in the top level of your site collection into either /Style Library/Themable or /Style Library/~language-code/Themable (such as /Style Library/en-us/Themable). The Themable folder is created automatically for publishing sites; if you don’t see it in the Style Library folder, you can just create your own folder. Just be sure to spell it properly! You can then drop in your styles and images into those folders, or into a subfolder if, like me, you want things to be somewhat organized.

5. Use <SharePoint:CssRegistration> to link your stylesheet

In your master page, you’ll have to use <SharePoint:CssRegistration> to link your stylesheet, like this:

<SharePoint:CssRegistration name="<% $SPUrl:~sitecollection/<em>location-of-stylesheet</em> %>" After="corev4.css" runat="server"/>

Here’s the example from my master page:

<SharePoint:CssRegistration name="<% $SPUrl:~sitecollection/Style%20Library/Themable/corriecustom/styles.css%>" After="corev4.css" runat="server"/>

6. Check and publish and change your theme

I tend to refresh often as I’m working on a custom master page design. If you’re trying to see how your themable changes affect your design, be sure to check in and publish your stylesheet and images. You will then need to apply a new theme so that SharePoint regenerates the themed files. Then, you’ll be able to see your changes! Below, you can see my site with my custom master page applied, after switching themes a few times!

Cay theme applied

Grapello theme applied

Resources and links

Color scheme tools and creating a SharePoint color theme

One of the first things I do when embarking on a new SharePoint branding project is to determine the color scheme. Sometimes, the colors are part of the design requirements, but often, I have some leeway in creating suggested color palettes to present to the client. Even if the client has provided a logo with one or two colors, I will still have to determine other colors that will be used in the design or site. For example, you may have one or more background colors to anchor the site, the primary text color, and one or more accent colors. I usually like to create my own color schemes, but if you aren’t sure where to start, or if you don’t think you have an “eye” for color, here are some tips to get you going.

Starting from scratch? Start with a photo.

If you have absolutely no requirements for colors but have to start from scratch, I often find it helpful to start with a nice photo. Some may find it hard to come up with an attractive color scheme on your own, but most people have an innate sense of “that looks nice” when they look at photos, even if they can’t exactly explain why. I tend to be inspired by nature photos, but you may also find interior decorating photos, wedding photos, or party photos inspiring as well. Find a photo that evokes the kind of feeling or mood that you’re going for with your web site — for example, soothing or exciting, subtle or vibrant, corporate or earthy…

IMG_3950 IMG_8889 IMG_2724 IMG_7711 DSC03772.JPG DSC03332.JPG

Use an online color scheme tool

When you have your logo or photo or even just one initial color, use an online color scheme tool to generate a palette of colors for your site. There are several tools that allow you to upload an image or enter an image URL to generate a color scheme based on the colors in the image; or, you can pick an initial color and then allow the tool to pick colors that go with it. I’ve pulled screenshots from two of the available tools so that you can see how they compare:

colorschemedesigner.com


In Color Scheme Designer, I entered in the RGB code for a mauve color (the input box is subtle – click on the RGB code to the bottom right of the color wheel and type in your desired color). I then selected “complement” from the color wheel choices above, and a set of colors was generated for me. What’s nice about this app is that you can view light page and dark page examples that use those colors – although you may not choose to use the colors quite like the way they display them, you may find it helpful to see how the colors look in the context of a web page. Below is the “light page” sample:

colorexplorer.com

ColorExplorer allows you to upload an image and then pulls out your desired number of colors from the image.

(Note: Another powerful color scheme generator is Adobe’s Kuler tool. Unfortunately as of this writing, it looks like they’re revamping it, and it should be back up mid-October 2012.)

Or, browse sites.

Of course, you can also browse web sites and find one where you like the color scheme and steal be inspired by it. Some nice web site galleries that I often visit include:

Making a quick SharePoint 2010 color change

Once I have a color scheme, I can then present the scheme to the client to see if they approve. But if you want to make a quick implementation in SharePoint with your color scheme to see how it looks, modify the Theme colors. Make note of the six-digit hexadecimal/RGB color codes from your color scheme before you begin.

Go to Site Settings and click the Site Theme link under Appearance.

Click on the “Select a color…” links to enter in your color codes.

Click “Apply” and your theme colors will be updated! Take a look and adjust the colors as you want.

Other resources

IE9 and SharePoint 2010 are not compatible for intranets, team sites, etc.

This is not something you want to learn while in the middle of a couple intranet branding projects for high-profile clients, but IE9 and SharePoint 2010 are not compatible for team sites. So say goodbye to the pretty intranet designs with CSS3 shadows and gradients and rounded corners and beautiful HTML5 code. Use CSS3 and HTML5 all you want on publishing public-facing sites, but for now, they just won’t work on the internal pages.

The main issue is referenced in this short SharePoint Forum post, SharePoint 2010 dialogs with rich-text controls don’t work in IE9. Basically, if you take out the meta tag that forces IE8 compatibility (<meta http-equiv=”X-UA-Compatible” content=”IE=8″ />) the dialog windows with rich-text controls stop working. You can’t edit the rich text fields, and you can’t “save” at all even if you don’t touch the rich text field. This obviously causes problems when you are trying to have an IE9-branded experience on pages such as calendars, tasks, etc. that use the rich text field editor.

I’m truly surprised that this hasn’t been fixed yet by the SharePoint team. If anyone has any ideas on how to circumvent this issue, I’d love to know it. (Besides the obvious and annoying answer of reverting all our pretty designs back to IE8, of course.)

Props to Heather Waterman for helping to pinpoint the issue.

Adding rounded corners to web part header for SharePoint 2010

I wanted to add rounded corners to the out-of-the-box web part header in a SharePoint 2010 site. Looking around in Google’s initial results, I found a couple references to Heather Solomon’s article about adding rounded corners to a web part header in a 2007 site, but I didn’t especially love that the rounded corner didn’t go all the way to the right edge:

At this point, I have to admit that I didn’t dive much further into Google results, but decided to have a go at it on my own. If I had spent a little bit of extra time, I might have found Rich Whitworth’s article about using jQuery to add classes to the table cells of the web part header which would then give you an easy way to hook in the CSS. Or I might have seen Kyle Schaeffer’s article on using CSS and images to add rounded corners, which is pretty close to what I ended up doing. … But I didn’t, so here’s what I ended up doing on my own.

I’m going to go through a couple different examples:

  • A gradient rounded header bar using images and CSS
  • A rounded header bar using CSS3

These will all be based on the same general principle, but perhaps the slight differences and examples will be helpful.

The basic idea

Here is the HTML for the table that holds the web part header. As you can see, the row has a class of .ms-WPHeader. Then, there are up to five table cells involved:

  • td.ms-wpTdSpace – the first spacer cell on the left
  • td.ms-WPHeaderTd – the cell that holds the title
  • td.ms-WPHeaderTdMenu – the cell with the dropdown arrow; only shows if you have editing privileges
  • td.ms-WPHeaderTdSelection – the cell with the select checkbox; only shows if you have editing privileges and if it’s available
  • td.ms-wpTdSpace – the last spacer cell on the right

In order to attach a background image or color, I’ll apply styles to all the table cells by using .ms-WPHeader td. To add on the rounded corners, I’ll apply styles to td.ms-wpTdSpace – the spacer cells on the left and right – and use the :first-child pseudo-class to target the left spacer cell and modify it as much as I need to. Finally, I’ll work with .ms-WPHeaderTdMenu, which has some border styles applied by the default core CSS and a hover background effect, so that it doesn’t clash with my new header bar styles.

Ready? Let’s go!

A gradient rounded header bar using images and CSS

Let’s start with a gradient rounded header bar using images and CSS, which will compatible across most browsers, including IE7 and 8. Here are the two images I’ll be using – “bg-bar.png” for the repeated background, and “bg-barcorners.png” for the left and right corners.

Now, let’s add the CSS. I’ll start with applying the repeated background image to all the table cells:

.ms-WPHeader td { background: url('../images/bg-bar.png') repeat-x; border-bottom: none !important;  }

Here’s what it looks like:

That little gap on the right has to do with some of the border settings on the .ms-WPHeaderTdMenu cell — we’ll deal with that later.

For now, let’s apply the rounded corners to the left and right table cells. I’ll apply the background image to any table cell with .ms-wpTdSpace and position it to show the top right, then use the :first-child pseudoclass to move the background image to the top left so that the corner shows up properly.

.ms-WPHeader td.ms-wpTdSpace { background: url('../images/bg-barcorners.png') top right; }
.ms-WPHeader td:first-child.ms-wpTdSpace { background-position: top left; }

Wasn’t that easy?

The rest of this is just fine-tuning. I’m going to change the color of the title text to be white (both the normal title text and any linked title text) and remove the border from .ms-WPHeaderTdMenu to get rid of that gap. I’ll also add some styling to the .ms-WPHeaderTdMenu hover state so that the hover effect goes more with my color scheme.

.ms-WPHeader h3, .ms-WPHeader h3 a { color: #fff; }
.ms-WPHeaderTdMenu { border: none !important; }
.s4-wpcell:hover .ms-WPHeader .ms-WPHeaderTdMenu:hover { background: #c3e298; }

Here’s how it looks now:

Here’s the complete CSS code for those of you who like to just copy and paste:

.ms-WPHeader td { background: url('../images/bg-bar.png') repeat-x; border-bottom: none !important;  }
.ms-WPHeader td.ms-wpTdSpace { background: url('../images/bg-barcorners.png') top right; }
.ms-WPHeader td:first-child.ms-wpTdSpace { background-position: top left; }
.ms-WPHeader h3, .ms-WPHeader h3 a { color: #fff; }
.ms-WPHeaderTdMenu { border: none !important; }
.s4-wpcell:hover .ms-WPHeader .ms-WPHeaderTdMenu:hover { background: #c3e298; }

A rounded header bar using CSS3

For an even quicker solution that doesn’t involve using images, you can use CSS3 to add rounded corners to the header bar. This solution won’t work in IE7 or IE8 but should work in IE9, Firefox, Safari, and Chrome.

If you look at the code below, I used a background color in place of a background image, then rounded the corners using CSS3 properties.

.ms-WPHeader td { background: #7bb42d; border-bottom: none !important;  }
.ms-WPHeader td.ms-wpTdSpace { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
.ms-WPHeader td:first-child.ms-wpTdSpace { -moz-border-radius-topright: 0px; -webkit-border-top-right-radius: 0px; border-top-right-radius: 0px; -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; }
.ms-WPHeader h3, .ms-WPHeader h3 a { color: #fff; }
.ms-WPHeaderTdMenu { border: none !important; }
.s4-wpcell:hover .ms-WPHeader .ms-WPHeaderTdMenu:hover { background: #c3e298; }

Here’s what it looks like:

You can even use CSS3 to add a background gradient to duplicate the look from my first example.

.ms-WPHeader td { background: #7bb42d; background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, rgb(124,180,45)), color-stop(1, rgb(176,210,128))); background-image: -moz-linear-gradient( center bottom, rgb(124,180,45) 0%, rgb(176,210,128) 100%); border-bottom: none !important;  }
.ms-WPHeader td.ms-wpTdSpace { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
.ms-WPHeader td:first-child.ms-wpTdSpace { -moz-border-radius-topright: 0px; -webkit-border-top-right-radius: 0px; border-top-right-radius: 0px; -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; }
.ms-WPHeader h3, .ms-WPHeader h3 a { color: #fff; }
.ms-WPHeaderTdMenu { border: none !important; }
.s4-wpcell:hover .ms-WPHeader .ms-WPHeaderTdMenu:hover { background: #c3e298; }

Just for an extra variation and a slightly different look, you can add rounded corners to the bottom edges of the web part header by using more border-radius properties. Notice that I also added .ms-WPBorder { border: none; } to remove the border from any web parts that might have the border showing.

.ms-WPHeader td { background: #7bb42d; background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, rgb(124,180,45)), color-stop(1, rgb(176,210,128))); background-image: -moz-linear-gradient( center bottom, rgb(124,180,45) 0%, rgb(176,210,128) 100%); border-bottom: none !important;  }
.ms-WPHeader td.ms-wpTdSpace { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
.ms-WPHeader td:first-child.ms-wpTdSpace { -moz-border-radius-topright: 0px; -webkit-border-top-right-radius: 0px; border-top-right-radius: 0px; -moz-border-radius-bottomright: 0px; -webkit-border-bottom-right-radius: 0px; border-bottom-right-radius: 0px; -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
.ms-WPHeader h3, .ms-WPHeader h3 a { color: #fff; }
.ms-WPHeaderTdMenu { border: none !important; }
.s4-wpcell:hover .ms-WPHeader .ms-WPHeaderTdMenu:hover { background: #c3e298; }
.ms-WPBorder { border: none; }

Hope you find this helpful!

References and additional resources

Customizing the HTML code of a Content Query Web Part

I’m learning all about SharePoint branding as part of my new job at Synteractive, so this post started out as a reference file and notes on the steps I was taking. It ended up being an insanely long blog draft and I decided to throw it out there to see if more experienced SharePoint superstars can give me some tips on how I could have done this more easily or maybe to help other newbie SharePoint developers.

Some facts and disclaimers:

  • I’m working with a SharePoint 2010 Publishing site and using SharePoint Designer 2010 for modifying some of the site files.
  • I’m not going to go into CSS in this article, so I won’t talk about how I style the web part. This article is really just about getting the HTML I want to be generated from a customized Content Query Web Part.
  • At this point, I’m literally just under three weeks into learning about SharePoint branding, customizing master pages, working with XSL, etc. I have a lot to learn.

Here is the challenge that I had:

First, here’s a screenshot of my custom query web part:

  • The CQWP pulls from a list of publishing pages and displays the title, a description, an image, and links to the page.
  • Of the three dummy data items there, #1 only has a title and link, #2 has a title, description, image, and link, and #3 only has the title, description, and link.
  • The CQWP is set up to use the “image on left” Item Style.

If you view the HTML source, there is a TON of HTML code that goes into the above; there are several nested tables and stuff for allowing you to click on the header to edit it. Here is just a small sampling…

<table class="s4-wpTopTable" border="0" cellpadding="0" cellspacing="0" width="100%">
	<tr>
		<td><table border="0" cellpadding="0" cellspacing="0" width="100%">
			<tr class="ms-WPHeader">

				<td align="left" class="ms-wpTdSpace"> </td>
				<td title="Recent News - Displays a dynamic view of content from your site." id="WebPartTitleWPQ2" class="ms-WPHeaderTd"><h3 style="text-align:justify;" class="ms-standardheader ms-WPTitle"><nobr><span>Recent News</span><span id="WebPartCaptionWPQ2"></span></nobr></h3></td>

The actual data part – the list of news items – has HTML code that looks like this:

<ul class="dfwp-column dfwp-list" style="width:100%" >
<li class="dfwp-item"><div class="item"><div class="link-item"><a href="#" title="">New SPDevWiki site released!</a><div class="description"></div></div></div></li>
<li class="dfwp-item"><div class="item"><div class="link-item"><a href="#" title="">SharePoint 2010 SDK released</a><div class="description">SharePoint 2010 SDK released for RTM</div></div></div></li>
<li class="dfwp-item"><div class="item"><div class="link-item"><a href="#" title="">Announcing Community Kit for SharePoint</a><div class="description">CodePlex projects teams get together to release CKS:Dev!</div></div></div></li>
</ul>

There are plenty of classes to work with… but if I were to modify the .dfwp-xxx classes, those would affect all of the web parts using that type of display, and in my specific situation, I couldn’t throw the web part into my own custom <div> with an ID or class that would allow me to target only that web part.

But I’m getting ahead of myself. Let me show you what I was shooting for. Here’s my HTML that I would ideally want:

<div class="blogfeed-wrapper">
	<div class="blogfeed">
		<h2>Recent News</h2>
		<ul>
			<li>
				<p class="date">Jun 5, 2010</p>
				<p class="image"><img src="images/pic.png" alt="image" width="50" height="50" /></p>
				<h3><a href="#">Article title</a></h3>
				<p class="blurb">Article blurb</p>
			</li>
			<!-- repeat LI for each data item -->
		</ul>
	</div>
</div>

To accomplish this, I would have to:

  1. Figure out how to wrap the DIVs and UL around the repeated list items, along with the H2 heading
  2. Modify the code for the repeated list items to use the HTML code I want (and to show the additional “article date” field)

I looked around for information about customizing the Content Query Web Part and found this article, “Display Content Query Web Part Results in a Grid/Table” by Paul Galvin which seemed like it might do the trick. He references Heather Solomon’s blog post, “Customizing the Content Query Web Part and Custom Item Styles.” Here are the step-by-steps of what I did:

  1. I followed Heather Solomon’s article, steps 5-11, and Paul Galvin’s step 4 to create a test item style in ItemStyle.xsl in order to list out the data already being pulled into the web part. I named my custom style “TestList” – I’ll keep it around for testing other web parts.
    1. In SharePoint Designer 2010, open Style Library/XSL Style Sheets/ItemStyle.xsl. Note that this file is only available in a root or top-level SharePoint site, not in subsites.
    2. Click the “Edit” link (in the “Customization” section).
    3. In ItemStyle.xsl, you’ll see a few <xsl:variable /> tags at the top, followed by sections of <xsl:template /> code. Each <xsl:template /> has a name associated with it which corresponds to the Item Style dropdown in the Web Part editor.
    4. Here’s the code I added – just to keep it easy to find, I put it under the “Default” template section. Also notice that the value for name and @Style must be identical.
      <xsl:template name="Default" match="*" mode="itemstyle">
      ....
      </xsl:template>
      <!-- custom item style template for listing out fields -->
      <xsl:template name="TestList" match="Row[@Style='TestList']" mode="itemstyle">
      	<xsl:for-each select="@*">
      		<xsl:value-of select="name()" /><br />
      	</xsl:for-each>
      </xsl:template>
    5. Back in the browser, click to edit the web part. In the web part editor, under Presentation > Styles, pick the new “TestList” from the list of Item Styles:
    6. Here’s what I ended up with:
    7. If you want, copy and paste the list into a text editor for reference just in case.
  2. Now, following steps 12-13 in Heather’s article, I went to find the specific column “Internal Names” for fields that I wanted to add to the web part.
    1. Go to Site Settings > Site Administration: Site Libraries and Lists. This page shows a list of the various types of lists and libraries in your site.
    2. I picked the “Pages” list because that’s what my Content Query Web Part is pulling, but you’ll want to go to whichever list you’re trying to pull data from. This takes you to the List Information page.
    3. Scroll down to the Columns section to view all the columns that are available for that type of content.
    4. Hover or click on the link for the columns that you want to add to the Content Query Web Part results. I’m primarily interested in the “Article Date” column. At the very end of the link is the “Field” parameter, followed by the internal column name. In my case, the Article Date column’s internal name is ArticleStartDate.
  3. Following steps 16-18 in Heather’s article, I export the CQWP, modify the code to include the extra column(s), then import it back in as a new web part.
    1. Back on the web site, expand the edit menu and choose “Export.”
    2. Save the .WEBPART file to your computer, then open it in a text editor.
    3. Look for “CommonViewFields” and you’ll see something like this:
      <property name="CommonViewFields" type="string" />
    4. Following Heather’s instructions, I modify the tag to include my additional ArticleStartDate column.
      <property name="CommonViewFields" type="string">ArticleStartDate, DateTime</property>

      Note: From this MSDN article, “How to Display Custom Fields in a Content by Query Web Part,” there’s an additional step (Step 4) to map the new column to existing/available fields in the web part. This only works if your custom field can replace the Title, Description, LinkURL, or ImageURL web part fields – which could save you a few steps if, say, you wanted to show a different text column in place of the “description” field. In this case, though, since I want to display the article date, I’m going to have to do some actual customization to the XSL files, described below.

    5. Save the file. Back in the browser, click the “Edit” button to edit the page so that you can add more web parts to the page.
    6. Click “Add a Web Part”, then click “Upload a Web Part” and browse to your .WEBPART file, then click Upload.
    7. You’ll have to click “Add a Web Part” again, but this time you’ll see an additional folder for “Imported Web Parts” with your new web part listed. Add this to your page. (Mine is called “Recent News” because it exported my original Content Query Web Part, which had “Recent News” as the title.)
    8. The new web part will show up on the page. Notice that the new column is included with the other data:
    9. Delete the original web part just to get it off the page.
  4. Now, I wanted to figure out how to modify the HTML to display what I wanted: Some outer wrapper DIVs for styling, an H2 heading for the “Recent News” title, a wrapper UL for the list items, and then using a simple LI for each list item. Bear with me as I explain the overall approach:
    1. First – I’m going to get rid of the existing “Recent News” heading by changing the Chrome of the web part to hide the current title and ONLY show the list itself. This will allow me to get rid of the funky tables and code that are really difficult to style. (I’m going to be inserting my own heading in the HTML instead.)
    2. Then – I’m going to do the “easy” part, which is to edit ItemStyle.xsl with my HTML for each list item (the <LI> and everything in between from the top of this page in my “ideal” HTML code). This will allow me to get rid of the various DIVs from the default “Image on Left” code, remove displayed fields that I don’t need, and add in the additional fields that I want to display (in this example, ArticleStartDate). Both Paul and Heather’s articles cover this part. Note: As mentioned in Heather’s article, ItemStyle.xsl “repeats” itself for each data item, which is why I would only put in the <LI> code. If I added <UL>, I would get a separate UL list for each item.
    3. Finally – the “hard” part, which is to edit ContentQueryMain.xsl to put in my wrapper DIVs, H2 heading, and UL, which will go around the stuff being generated in ItemStyle.xsl and make everything look pretty. This is where I turned to Paul’s article.
  5. Here we go! Starting with 4a: Hide the web part title bar by editing the web part and changing the Chrome Type to “None.”

    Note: If you were to save/close or check in the page, you’ll just see the list of data fields without the title bar.

    If you’re like me, you may freak out initially: “What have I done?! Now I can’t edit the web part!” No worries – as soon as you click “Edit page,” you’ll see your web part zones and the title bar will reappear for editing.
  6. Pulling from Heather’s article (steps 19-24), I open ItemStyle.xsl (again) in SharePoint Designer for editing.
    1. At this point, I already have an idea of the Item Style that I want to start from – the “Image on Left” style, because it already will contain the code I need for the image, title, and description, so all I need to do is move things around and add the date. You will need to figure out which Item Style you want to start with and find the corresponding code.
    2. In this case, “Image on Left” happens to be the same as the “default” template, so I find the 60 or so lines of code that make up the Default template, copy, and paste it under my TestList template.
      <xsl:template name="Default" match="*" mode="itemstyle">
      ....
      </xsl:template>
    3. My first step is to replace <xsl:template name=”Default” match=”*” mode=”itemstyle”> with something that looks more like my TestList template line, but with yet another custom Item Style name. I’ll call mine “News”:
      <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">

      In other words, replace name=”YourCustomStyleName” and match=”Row[@Style=’YourCustomStyleName‘]” in your <xsl:template> tag.

    4. Now, each xsl:template section has some variables or parameters at the top, followed by recognizable HTML code mixed in with various xsl tags for testing conditionals or displaying data. I copy the “ideal HTML” that I want to have and paste it into the top of that section to start me off.
      <li>
      	<p class="date">Jun 5, 2010</p>
      	<p class="image"><img src="images/pic.png" alt="image" width="50" height="50" /></p>
      	<h3><a href="#">Article title</a></h3>
      	<p class="blurb">Article text</p>
      </li>
      
    5. Then, start moving the relevant XSL code into your HTML tags.You can see what I did below. I had to add the ArticleStartDate field (see Step 20 in Heather’s blog) and formatted it by following the steps at Josh Gaffey’s blog for Custom Date Formats in SharePoint so that the date is displayed as m/d/yyyy. (Note that I put stuff I don’t really care about… or don’t understand what they do… in a comment tag to hide them.)
      <!-- custom item style template for recent news -->
      <xsl:template name="News" match="Row[@Style='News']" mode="itemstyle">
          <xsl:variable name="SafeLinkUrl">
              <xsl:call-template name="OuterTemplate.GetSafeLink">
                  <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
              </xsl:call-template>
          </xsl:variable>
          <xsl:variable name="SafeImageUrl">
              <xsl:call-template name="OuterTemplate.GetSafeStaticUrl">
                  <xsl:with-param name="UrlColumnName" select="'ImageUrl'"/>
              </xsl:call-template>
          </xsl:variable>
          <xsl:variable name="DisplayTitle">
              <xsl:call-template name="OuterTemplate.GetTitle">
                  <xsl:with-param name="Title" select="@Title"/>
                  <xsl:with-param name="UrlColumnName" select="'LinkUrl'"/>
              </xsl:call-template>
          </xsl:variable>
      
      	<li>
      		<!-- Here is where I add in my ArticleStartDate field. It would typically look like
      		<xsl:value-of select="@ArticleStartDate" />
      		but the extra stuff is to format the date. -->
      		<p class="date"><xsl:value-of select="ddwrt:FormatDate(@ArticleStartDate,1033,1)" /></p>
      
      		<xsl:if test="string-length($SafeImageUrl) != 0">
                  <p class="image">
                      <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}">
                          <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>
                  </p>
              </xsl:if>
      
      		<h3><a href="{$SafeLinkUrl}" title="{@LinkToolTip}"><xsl:value-of select="$DisplayTitle"/></a></h3>
      		<p class="blurb"><xsl:value-of select="@Description" /></p>
      
      		<!--
      		<xsl:call-template name="OuterTemplate.CallPresenceStatusIconTemplate"/>
                  <a href="{$SafeLinkUrl}" title="{@LinkToolTip}">
                    <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>
      
                  </a>
                  -->
      	</li>
      </xsl:template>
      
    6. When you’re done, go back into the browser to edit the web part. You should see your new custom item style in the Item Style select box. In the screenshot below, you can see that “News” (the name of my custom Item Style) showed up properly, so I was able to pick it and apply it. Of course, I’m still missing the wrapper HTML code (for the UL, etc.) so I moved on to the next step…
  7. Now I want to get the wrapper HTML code (below) around the LIs.
    <div class="blogfeed-wrapper">
    	<div class="blogfeed">
    		<h2>Recent News</h2>
    		<ul>
    		...
    		</ul>
    	</div>
    </div>
    

    At first glance, Paul’s article seems perfect for what I need to do. His method is to edit ContentQueryMain.xsl to pass in parameters that identify the “current position” and “last row” so that ItemStyle.xsl can put in special code at the start of the list (when current position = 0) and the end of the list (current position = last row). Unfortunately, after following his detailed and clear instructions, I found that it didn’t work for me. I’m not sure if it’s because of a difference in SharePoint 2007 and 2010, but basically what was going on was that the .dfwp-xxxx UL and LIs were still being wrapped around my code. So while Paul’s technique “worked” in the sense that the wrapper code showed up before the first item and after the last item, the other stuff was getting in the way and creating havoc with the code:

    <ul class="dfwp-column dfwp-list" style="width:100%" >
    <li class="dfwp-item">
    	<div class="blogfeed-wrapper">
    		<div class="blogfeed">
    			<h2>Recent News</h2>
    			<ul>
    			<li>...</li>
    </li>
    <li class="dfwp-item">
    			<li>...</li>
    </li>
    <li class="dfwp-item">
    			<li>...</li>
    			</ul>
    		</div>
    	</div>
    </li>
    </ul>
    

    Diving deep into the ContentQueryMain.xsl file, I was able to locate various variable definitions that hold the HTML code for the UL and LI tags. There were some variables near the top of the file and more inside the OuterTemplate.Body template.

    <xsl:variable name="BeginList" select="string('&lt;ul class=&quot;dfwp-list&quot;&gt;')" />
    <xsl:variable name="EndList" select="string('&lt;/ul&gt;')" />
    <xsl:variable name="BeginListItem" select="string('&lt;li class=&quot;dfwp-item&quot;&gt;')" />
    <xsl:variable name="EndListItem" select="string('&lt;/li&gt;')" />
    
    <xsl:template name="OuterTemplate.Body">
    	...
    	<xsl:variable name="BeginColumn1" select="string('&lt;ul class=&quot;dfwp-column dfwp-list&quot; style=&quot;width:')" />
    	<xsl:variable name="BeginColumn2" select="string('%&quot; &gt;')" />
    	<xsl:variable name="BeginColumn" select="concat($BeginColumn1, $cbq_columnwidth, $BeginColumn2)" />
    	<xsl:variable name="EndColumn" select="string('&lt;/ul&gt;')" />
    

    If you do a quick search in the code for $BeginList, $EndList, etc., you’ll see that those variables are printed out several times in different places. Not being at all an expert, though, it was pretty hard for me to figure out what was going on, so I resorted to an elegant solution to find the places to target. And by “elegant,” I mean “amateurish and hackish.” If you aren’t too embarrassed to follow my example, here’s what you do…

  8. Go through all of the code, looked for all the instances where those variables are printed out, and add test text before them that will print out in the HTML and show which conditionals were being fulfilled. Here’s one example:
    TEST1
    <xsl:value of disable-output-escaping="yes" select="$BeginColumn" />
    

    You’ll want to repeat that for each time you see an <xsl:value /> tag for $BeginList, $EndList, $BeginListItem, $EndListItem, $BeginColumn, and $EndColumn.

    When I saved and refreshed my browser, this is what I saw:

  9. Now you can go through the code, find the places where your test code was added, and replace them with your custom code. Below are the steps that I took, but you’ll need to figure out what will work for you.
    1. My first step was to set up my own custom variables for the wrapper. Inside the OuterTemplate.Body, under the existing variable definitions for BeginColumn1, BeginColumn2, etc., I added this custom code below. Since I didn’t feel like dealing with lots of &lt; and &gt;, I put my HTML code inside a CDATA section:
      <!-- my custom variables for the news section -->
      <xsl:variable name="newsStart">
      	<![CDATA[
      		<div class="blogfeed-wrapper">
      			<div class="blogfeed">
      				<h2>Recent News</h2>
      				<ul>
      
      	]]>
      </xsl:variable>
      <xsl:variable name="newsEnd">
      	<![CDATA[
      				</ul>
      			</div>
      		</div>
      
      	]]>
      </xsl:variable>
      
      
    2. Okay, NOW I’m ready to replace my “TEST#” stuff with actual useful code. I looked for TEST1 (start of list), TEST9 (start of list item), TEST10 (end of list item), and TEST6 (end of list) in the ContentQueryMain.xsl file. I added <xsl:choose /> and <xsl:when /> statements to put in my custom variables when the Item Style = “News” (the name of my custom item style).Here is the original code (with the first TEST1 stuck in there):
      <xsl:choose>
          <xsl:when test="$cbq_isgrouping != 'True'">
              <xsl:if test="$CurPosition = $FirstRow">
      		TEST1
      		<xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
              </xsl:if>
          </xsl:when>
      

      And here’s my edited code:

      <xsl:choose>
          <xsl:when test="$cbq_isgrouping != 'True'">
              <xsl:if test="$CurPosition = $FirstRow">
              <!-- customized stuff -->
      		<xsl:choose>
              	<xsl:when test="@Style='News'">
              		<xsl:value-of disable-output-escaping="yes" select="$newsStart" />
      			</xsl:when>
      			<xsl:otherwise>
      				<!-- this was the original code -->
      				<xsl:value-of disable-output-escaping="yes" select="$BeginColumn" />
      			</xsl:otherwise>
              </xsl:choose>
              <!-- end customized stuff -->
      
              </xsl:if>
          </xsl:when>
      
    3. I repeated the process for the other sections. Because my <li> and </li> is inside the ItemStyle.xsl file, I didn’t need to define variables for those and left those “when” statements empty.
      <!-- customized stuff -->
      <xsl:choose>
      	<xsl:when test="@Style='News'">
      		<xsl:value-of disable-output-escaping="yes" select="$newsEnd" />
      	</xsl:when>
      	<xsl:otherwise>
      		<!-- this was the original code -->
      		<xsl:value-of disable-output-escaping="yes" select="$EndColumn" />
      	</xsl:otherwise>
      </xsl:choose>
      <!-- end customized stuff -->
      
      ...
      
      <xsl:template name="OuterTemplate.CallItemTemplate">
          <xsl:param name="CurPosition" />
          <xsl:param name="LastRow" />
          <!-- customized stuff -->
      	<xsl:choose>
          	<xsl:when test="@Style='News'" />
      	<xsl:otherwise>
      		<!-- this was the original code -->
      		<xsl:value-of disable-output-escaping="yes" select="$BeginListItem" />
      	</xsl:otherwise>
          </xsl:choose>
          <!-- end customized stuff -->
      
      ...
      
      <!-- customized stuff -->
      <xsl:choose>
      	<xsl:when test="@Style='News'" />
      	<xsl:otherwise>
      		<!-- this was the original code -->
      		<xsl:value-of disable-output-escaping="yes" select="$EndListItem" />
      	</xsl:otherwise>
      </xsl:choose>
      <!-- end customized stuff -->
      
      
    4. And after saving the page, going back to the browser, and refreshing, I finally have my desired result! (Note that the colors and layout are all part of my stylesheet, which I’m not delving into for this article.)

      Here is what the HTML looks like (I took out the URLs and added line breaks for legibility). It’s much cleaner than the original generated HTML and includes the classes that I need to hook in my CSS!

      <div class="blogfeed-wrapper">
      	<div class="blogfeed">
      		<h2>Recent News</h2>
      		<ul>
      			<li xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">
      				<p class="date"></p>
      				<h3><a href="..." title="">New SPDevWiki site released!</a></h3>
      				<p class="blurb"></p>
      			</li>
      			<li xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">
      				<p class="date">8/3/2010</p>
      				<p class="image"><a href="..."><img class="image" src=".../image.png" title="" /></a></p>
      				<h3><a href="..." title="">SharePoint 2010 SDK released</a></h3>
      				<p class="blurb">SharePoint 2010 SDK released for RTM</p>
      			</li>
      			<li xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime">
      				<p class="date">6/4/2010</p>
      				<h3><a href="..." title="">Announcing Community Kit for SharePoint</a></h3>
      				<p class="blurb">CodePlex projects teams get together to release CKS:Dev!</p>
      			</li>
      		</ul>
      	</div>
      </div>
      

Whew! That was really long. Here’s a summary of the steps that I took:

  1. Created a custom “test” Item Style to list out the fields being passed to the web part, which also helped after Step 3 to see if the new fields were added in properly or not.
  2. Figured out the internal column name(s) for the additional field(s) to add to the web part.
  3. Exported the Custom Query Web Part that was on the page, modified the code to add the fields, and imported the modified web part back in and added it to the page.
  4. Changed the Chrome type to “none” to hide the title bar.
  5. Created a custom “News” Item Style and modified the code to get the HTML that I wanted to display for each item.
  6. Hacked ContentQueryMain.xsl to figure out where to modify the code, then added custom code specific to the “News” Item Style for my wrap-around code.

I definitely appreciate any comments that more experienced SharePoint developers have about how to modify the ContentQueryMain.xsl file more elegantly or other ways to accomplish this! If you have questions, please feel free to post them but remember that I’m new to this as well and may not be able to answer them.😉

References and acknowledgements