Hello NothingButSharePoint.com!

I’ve recently joined as an author on NothingButSharePoint.com! Exciting to be able to join the SharePoint community a little more and hopefully contribute to the collective SharePoint knowledge online. Check out my first posting: jQuery Slideshow (Carousel) in Sharepoint 2010.

Create jQuery Tabs in Sharepoint 2010

This post will show you how to create a tabbed interface using Sharepoint Designer and some basic jQuery skills. I do not profess to know everything about jQuery, but this is getting the job done hopefully without too sloppy of code. Watch the screencast (no audio), then follow the instructions below.

Click to skip ahead:
Setup
Create the Tab Structure
Create the Panel Structure
Add the jQuery
Full Code + CSS


Setup


Create a blank aspx page in Sharepoint Designer. Other than that top 5 lines of Sharepoint code that all begin with “<%", take everything else out. The two things you will need are 1) the placeholder for additional page head for holding any css and the jQuery scripts,

<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">

and 2) the main placeholder, for holding the actual tabs.

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">


Create the Tab Structure


You'll create the tabs with an unordered list. It's important to give each tab two classes. One that designates it as a tab (mine is "choice"); one that designates which division it is (mine is "hs" or "ms", etc.); and you'll also want to make one tab activated by default. This is done by adding the CSS class "activated". You could also do this with jQuery if you wanted. Check the code at the bottom for all of the wrapping divs that will work with jQuery.

<ul class="div-nav">
<li class="choice show-hs activated">High School</li>
<li class="choice show-ms">Middle School</li>
<li class="choice show-es">Elementary School</li>
</ul>


Create the Panel Structure


Each panel needs two classes as well. One will designate it as a panel (mine is "webpart"); and one will designate which division it is (again, "hs", "ms", etc.). For testing purposes just put some plain text in each panel so you can confirm the tabbing is working. After that, you can put anything inside. For instance, on my production page I am loading 16 (yes, a bit worrisome) Content Query WebParts, yet only a few are showing at a time because of my tab system. Again, check the code at the bottom for all of the wrapping divs that will work with jQuery.

<div class="webpart hs">High School Stuff</div>
<div class="webpart ms">Middle School Stuff</div> 
<div class="webpart es">Elementary School Stuff</div>


Add the jQuery


First, make sure you're calling the jQuery script (I have a local copy installed). Then I'll split up my code into several parts and explain it.

I've wrapped everything in a function that runs when the tabs are loaded and ready to go:

$("ul.div-nav").ready(function(){
});

Then I hide all of the panels, and fade in the first one (in this case the High School panel, as I have the High School tab activated).

$("#daily-wrapper .webpart").hide();
$("#daily-wrapper .webpart.hs").fadeIn('slow');

Next I set the tab magic. Each tab needs to have a toggleClass attribute attached to it so you'll know which tab you're on. Then you'll want to deactivate the activated class on all other tabs.

$("ul.div-nav li.choice").click(function(){$(this).toggleClass("activated")});
$("ul.div-nav li.choice").click(function(){$(this).siblings("ul.div-nav li").removeClass("activated")});

Finally, anytime a tab is clicked I fade everything out, and then only fade in the particular panel that the tab calls for.

$("ul.div-nav li.choice").click(function(){$("#daily-wrapper .webpart").fadeOut('fast')});
$("ul.div-nav li.show-hs").click(function(){$("#daily-wrapper .webpart.hs").fadeIn('slow')});
$("ul.div-nav li.show-ms").click(function(){$("#daily-wrapper .webpart.ms").fadeIn('slow')});
$("ul.div-nav li.show-es").click(function(){$("#daily-wrapper .webpart.es").fadeIn('slow')});

As you can see, it's actually quite basic. I'm sure there are some things here against best practice, and definitely let me know if you find a better way of accomplishing this. But this seems to work for us.


Full Code (CSS Below)

<%@ Register tagprefix="WebControls" namespace="Microsoft.SharePoint.Publishing.WebControls" assembly="Microsoft.SharePoint.Publishing, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%-- _lcid="1033" _version="14.0.4762" _dal="1" --%>
<%-- _LocalBinding --%>
<%@ Page language="C#" MasterPageFile="~masterurl/default.master"    Inherits="Microsoft.SharePoint.WebPartPages.WebPartPage,Microsoft.SharePoint,Version=14.0.0.0,Culture=neutral,PublicKeyToken=71e9bce111e9429c" meta:webpartpageexpansion="full" meta:progid="SharePoint.WebPartPage.Document"  %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %> <%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceHolderId="PlaceHolderAdditionalPageHead" runat="server">
<script type="text/javascript" src="/Style Library/scripts/jquery.js"></script>
<script type="text/javascript">
$("ul.div-nav").ready(function() {
	$("#daily-wrapper .webpart").hide();
	$("#daily-wrapper .webpart.hs").fadeIn('slow');
	$("ul.div-nav li.choice").click(function(){$(this).toggleClass("activated")});
	$("ul.div-nav li.choice").click(function(){$(this).siblings("ul.div-nav li").removeClass("activated")});
	$("ul.div-nav li.choice").click(function(){$("#daily-wrapper .webpart").fadeOut('fast')});
	$("ul.div-nav li.show-hs").click(function(){$("#daily-wrapper .webpart.hs").fadeIn('slow')});
	$("ul.div-nav li.show-ms").click(function(){$("#daily-wrapper .webpart.ms").fadeIn('slow')});
	$("ul.div-nav li.show-es").click(function(){$("#daily-wrapper .webpart.es").fadeIn('slow')});
});
</script>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<div id="daily-wrapper">
<ul class="div-nav">
<li class="choice show-hs activated">High School</li>
<li class="choice show-ms">Middle School</li>
<li class="choice show-es">Elementary School</li>
</ul>
<div class="content">
<div class="calendar">
<h2>Calendar</h2>
<div class="webpart hs">High School Stuff</div>
<div class="webpart ms">Middle School Stuff</div> 
<div class="webpart es">Elementary School Stuff</div>
</div>
</div>
</div>
</asp:Content>

Full CSS


#daily-wrapper ul.div-nav li {
	font-size:1.2em;
	margin:0px;
	border-right:1px solid #fff;
}
#daily-wrapper .calendar {
	position:relative;
	border:0px solid #333;
	width:67%;
	float:left;
}
#daily-wrapper .calendar {
	margin-right:19px;
	width:30%
}

#daily-wrapper .content .calendar h2 {
	color:#fff;
	text-indent:-9999px;
	height:64px;
	background: #fff url('/Style Library/images/calendar-header.jpg') no-repeat top left;
	margin-bottom:20px;
}

ul.div-nav {
	width:100%;
	background:#999;
	float:left;
	text-align:center;
}
ul.div-nav li {
	display:block;
	float:left;
	color:#fff;
	text-decoration:none;
	padding:10px;
}
ul.div-nav li:hover {
	background:#b80000;
	cursor:pointer;
}
ul.div-nav li.activated {background:#b80000;}

Create a feedback button for Sharepoint 2010

Ever want to get feedback from your users without making them go through some laborious process of filling out a survey or sending an email to the helpdesk?

Introducing: the feedback button. It allows your users, no matter what page they are on, to submit their feedback. I’ve found this to be an extremely useful tool for gathering, you guessed it, feedback. And now I’ll teach you how to create one.

Click below to skip ahead:
Create a new list: feedback
Apply the workflow
Edit your master page


Create a new list: feedback


The first step in making this feedback button is to make a custom list into which your feedback will be input. For my list I have two columns. The first column (renamed the required “title” column) is “What page are you on?” I haven’t made the system intelligent, I’m leaving it up to the user to tell me where they are on the site. You never know, it could provide a little hint if they have no idea where they are, or they think they are somewhere they are not. The second column I create is a multi-line textbox column called “Comments”. That’s all I want from my users. Their feedback. Simple.

List Settings

  • Turn approval off, turn off version history
  • Item-level read permissions: read items that were created by the user
  • Item-level create/edit permissions: create items and edit items that were created by the user
  • Disable items to show in search results

Permissions
You’ll want to break permissions on this specific list and allow your users to have contribute permissions on this list alone. Otherwise they will not be able to submit items when they click the feedback button.


Apply the workflow


Create a new workflow on this list called “Feedback Workflow”. I always turn the start options to “start automatically when item is created”. That is really the only scenario with this list.

There is only one step in the workflow, and it should be an “email” step. If you check out my settings, I have put the contents of the comment box, including who wrote it, when they created it, and the page they were on.

Don’t forget to save and publish the workflow!


Edit your master page


This bit is slightly tricky. Not only do you need to put the button on your master page sidebar, but it needs to open the form in a modal dialog box window (at least that’s my preference). So below you’ll see the javascript I use to enable that dialog box on the link:

<div class="feedback"><a href="javascript;" onClick="javascript:SP.UI.ModalDialog.showModalDialog({ url: '/Lists/Feedback/NewForm.aspx', title: 'Add item' }); return false;"><h4>Questions?</h4><span>Click to send feedback</span></a></div>

Also, for some reason you want to style your feedback button like mine is style, here’s my CSS:

.feedback {
	margin-top:10px;
	text-align:center;
}
.feedback a {
	text-decoration:none;
	color:inherit;
	background:transparent url('/Style Library/images/feedback.png') no-repeat top center;
	display:block;
	height:40px;
}
.feedback a:hover {
	background:transparent url('/Style Library/images/feedback.png') no-repeat bottom center;
}
.feedback a h4 {
	color:#FFFF99;
	font-family:'Ubuntu Bold';
	font-weight:bold;
	font-size:1.3em;
	padding-top:2px;
}
.feedback a span {
	color:#ffffff;
	font-size:0.9em;
}

Itemstyle.xsl in SharePoint 2010: A guide for designers

Arguably the most useful tool in SharePoint 2010 is the Content Query WebPart (CQWP). This little webpart allows you rollup content from anywhere in the site collection and display it however you like. Yes, it has limitations, but this post is about the things you can do with it. But of course the CQWP is incomplete without a working knowledge of xsl styles. In SharePoint, all styles for the CQWP are stored in itemstyle.xsl. I’m not going to go into creating your own stylesheets, linking to CQWPs, etc. You can figure that out. We will dive into what is possible with styling CQWP results.

We’ll be creating something like this:

Skip ahead:

Create your list

Before we begin, create a list with the following columns:
Title (standard text field)
Body (rich text area)
SiteLink (hyperlink column)

Declare a new style and insert fields

Every new style in itemstyle.xsl must be wrapped in the following tags:

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

Inside this tag, we’ll begin by simply adding in our fields. I like to bring in all my fields, confirm they work on the page, and then begin styling.

<xsl:value-of select="@Title"/>
<xsl:value-of select="@Body"/>
<xsl:value-of select="@Author"/>
<xsl:value-of select="@SiteLink"/>

When you call a variable, it is either already built into the system (Title, Author), or you will need to customize it in the browser to add in your specific fields into those value placeholders.

The first thing we’ll do is format the hyperlink field to make it a friendly URL. The field, by default, puts the URL and then the friendly name concatenated together, but separated by a column. So what we do is create two variables in xsl, one that pulls everything before the comma, one that pulls everything after the comma. Then we will put the URL into an “a” tag.

<xsl:variable name="SiteLink" select="substring-before(@SiteLink,',')"/>
<xsl:variable name="SiteName" select="substring-after(@SiteLink,',')"/>
Link: <a href="{$SiteLink}"><xsl:value-of select="$SiteName"/></a>

Link Author to their mysite

Next, I want to take the Author’s name and link it to their MySite profile. To do that we are going to create a new variable that takes the login ID of the user (using ddwrt:UserLookup on the @Author tag). Once we have that ID we’re going to pass it into a parameter of the mysite URL.

<xsl:variable name="authoremail">
<xsl:value-of select="ddwrt:UserLookup(string(@Author) ,'Login')" />
</xsl:variable>
Questions about this? Contact <a href="https://m.domainname.com/Person.aspx?accountname={$authoremail}"><xsl:value-of select="@Author" /></a>

Format the Body to use markup

Your body content probably includes all the markup at the moment. The quick fix to that is adding in a disable-output-escaping=”yes” attribute.

<xsl:value-of select="@Body" disable-output-escaping="yes"/>

Final Code

Finally, just add some divs with classes to style. Here is my final code.

<xsl:template name="testannouncement" match="Row[@Style='testannouncement']" mode="itemstyle">
<xsl:variable name="SiteLink" select="substring-before(@SiteLink,',')"/>
<xsl:variable name="SiteName" select="substring-after(@SiteLink,',')"/>
<xsl:variable name="authoremail">
<xsl:value-of select="ddwrt:UserLookup(string(@Author) ,'Login')" />
</xsl:variable>
<div id="DailyAnnouncement">
<div class="title"><h4><xsl:value-of select="@Title"/></h4></div>
<div class="details">
<xsl:value-of select="@Body" disable-output-escaping="yes"/>
<xsl:if test="@SiteLink != ''">
<br/>Link: <a href="{$SiteLink}"><xsl:value-of select="$SiteName"/></a>

</xsl:if>
</div>
 <div class="contactemail">Questions about this? Contact
	<a href="https://m.domainname.com/Person.aspx?accountname={$authoremail}">
	<xsl:value-of select="@Author" />
	</a>
 </div>
</div>
</xsl:template>

Here’s my CSS for the itemstyle.xsl styles

#DailyAnnouncement {
	display:block;
	border:1px solid #fff;
	padding-right:5px;
}
#DailyAnnouncement div.title h4 {
	margin:0px;
	padding:0px;
	line-height:normal;
	background:#efefef;
	border:1px solid #ccc;
	padding:4px;
	background:#efefef url('/PublishingImages/Logos/announcement.gif') no-repeat 0px 0px;
	padding-left:35px;
	display:block;
}

#DailyAnnouncement div.details {
	border:1px solid #ccc;
	border-top:0px;
	padding:10px;
	display:block;
}

#DailyAnnouncement div.contactemail {
	background:#efefef;
	padding:4px;
	text-align:right;
	border:1px solid #ccc;
	border-top:0px;
}

Create a Search Scope for a Sharepoint 2010 List or Library

Screencast tutorial (notes below):

This tutorial explains how to create a search scope for a SharePoint 2010 list or library. As a side note, you may be interested to read how to create a jQuery instant filter for a list or CQWP.

Step 1: Go to Site Actions > Site Settings (make sure you’re in the root site), and click “Search scopes”.

Search Scope Settings

Step 2: Click “New Scope” to create a new scope to load in a sub-page of the site.
New Search Scope

Step 3: Nothing really needs to be set on this screen except the title. If you want this to be a default scope that shows in the normal scope dropdown, make sure and select the “Search Dropdown” box. Otherwise, everything can be set in your custom page.
Edit Search Scope Settings
Step 4: In the next screen you’ll see your newly created scope under “Unused Scopes”. There are no rules attached to this scope yet, so let’s go create some. Click “Add rules”.
Add rules to SharePoint Search Scope
If you want this search scope to query a specific list (for instance, I wanted it to troll through the “newlist” list), enter the address of the list in the “folder” textbox. Also, if you check “require” it will designate that only this list will be searched.
Search Scope rule settings
I’m not exactly sure how often the scopes update, but it seems to be about every 15 minutes. I assume it depends on how your server is setup.

Step 5: Next, create a new page. In this page, add some webparts. Add the following 3 webparts:

  • Search Box
  • Search Core Results
  • Search Paging


Search Box
When you add the search box webpart, the only thing I would change is the page which displays the result. I want to display the results on this page, not on the typical search page. So I just put the address of the page I’m on. That way it will send the search results to this page’s results webpart.

Search Core Results
Here is where you need to input the scope. Edit the webpart and look for the “location properties” section. Under “Scope” type the name of your scope (human readable is fine).

Click OK, reload the page, do a search, and now the search results should only show items in your list! Tada!

If you liked this article, check out how to create a jQuery instant filter.

devConnections

Heading off to devConnections in Las Vegas next week. Anybody else going to be there?

jQuery Slideshow (Carousel) in Sharepoint 2010

This blog is also featured on NothingButSharePoint.com
Note: This post was updated Dec. 5 to correct a few errors in the code markup.

This is a solution to create a jQuery slider (carousel) in Sharepoint 2010. It is based on an image library, and uses the tinycarousel jQuery plugin. [Read more...]