WSS v3 Flyout Menus

I’m used to using flyouts in the tabbed navigation in MOSS to enhance the navigation capabilities.  (See my earlier post on this to find out how to make it happen.)

Today I wanted to do the same thing in a WSS master page, but just changing the MaximumDynamicDisplayLevels value wasn’t working.  I found this post from Eric Shupps that explained why.  Depending on how you set up your WSS Site Collection, you may need to replace:

<asp:SiteMapDataSource
ShowStartingNode="False"
SiteMapProvider="SPNavigationProvider"
id="topSiteMap"
runat="server"
StartingNodeUrl="sid:1002" / >

in your master page with this:

<asp:SiteMapDataSource
ShowStartingNode="True"
SiteMapProvider="SPSiteMapProvider"
id="topSiteMap"
runat="server" />

See Eric’s post for more details.

Note added 2/6:

I don’t know why it didn’t occur to me before, but this also works for the left Quick Launch menu.  In that case, you will want to replace:

<asp:SiteMapDataSource
SiteMapProvider="SPNavigationProvider"
ShowStartingNode="False"
id="QuickLaunchSiteMap"
StartingNodeUrl="sid:1025"
runat="server" />

in your master page with this:

<asp:SiteMapDataSource
SiteMapProvider="SPSiteMapProvider"
ShowStartingNode="True"
id="QuickLaunchSiteMap"
runat="server" />
Technorati tags: , ,

Firing an Event When a User Selects a Value from a Data View Web Part Dropdown

I was skimming my old postings, and I realized that in a previous post, I had said that I would post about firing an event when a user selects a value from a DVWP dropdown.  Better late than never, I guess.

When you create a dropdown type of DVWP through the UI in SharePoint Designer, the dropdown is created just fine, but there is absolutely nothing there to make that dropdown actually *do* anything.  Helpful, but not much.  Here’s how you can make it worth something.

In this example, my goal was to pass the chosen value to another page through the query string (There are other ways to do this, but for this client, there was auditing software that made having the value in the URL of use.) so that I could display the set of items that were created during a specific archive period.  (I had a calculated column that gave the archive period based on the published date — see this post on how that works.)

  • Add a DVWP to the page
  • Drop the column you want to see onto it
  • Change layout and choose the second from the bottom option — Dropdown menu of titles

To get at the query string variable ArchivePeriod (seen in the code below referred to as $ArchivePeriod) you go to the DVWP ‘Common Dataview Tasks’ (click on the little > button to the right on the DVWP), and set up a Parameter as seen in the screen snippet below.  If you search the code for the page for ArchivePeriod after doing this, you can see the effect of your actions.  You can, in fact, add the variable directly into code, as you see! (There are two lines for ArchivePeriod now.)

Data View Parameters

The key portions of the code that SharePoint creates when you add this DVWP to the page as in the three steps above are as follows:

<xsl:template name="dvt_1">
...
<select name="ID" size="1">
<option selected="true" value="0">Choose One...</option>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows" />
<xsl:with-param name="FirstRow" select="1" />
<xsl:with-param name="LastRow" select="$dvt_RowCount" />
</xsl:call-template>
</select>

and

<xsl:template name="dvt_1.rowview">
<option>
<xsl:value-of select="@Archive_x0020_Period" />
</option>
</xsl:template>

While Designer has created a nice dropdown for you, nothing will happen if you make a selection; that work is left to you.  Here are the changes that I made; I’ve explained the changes below.

<xsl:template name="dvt_1">
...
<select size="1" onchange="HandleFilterSelection('default.aspx', 'PageFilterArchive.aspx', 'ArchivePeriod', this.options[selectedIndex].value)">
<xsl:choose>
<xsl:when test="not(string-length($ArchivePeriod))" >
<option value="0">Choose Dates</option>
</xsl:when>
<xsl:otherwise>
<option value="*">All Dates</option>
</xsl:otherwise>
</xsl:choose>
<xsl:call-template name="dvt_1.body">
<xsl:with-param name="Rows" select="$Rows" />
</xsl:call-template>
</select>

<xsl:template name="dvt_1.rowview">
<xsl:variable name="NewGroup" select="ddwrt:NameChanged(string(@Archive_x0020_Period), 0)" />
<xsl:if test="string-length($NewGroup)">
    <option>
<xsl:if test="$ArchivePeriod = @Archive_x0020_Period">
<xsl:attribute name="selected">
<xsl:value-of select="selected" />
</xsl:attribute>
</xsl:if>
<xsl:attribute name="value">
<xsl:value-of select="@Archive_x0020_Period" />
</xsl:attribute>
<xsl:value-of select="@Archive_x0020_Period" />
</option>
</xsl:if>
</xsl:template>

function HandleFilterSelection(defaultpath, filterpath, parameter, selection)
{
if(selection == "*")
{
document.location.href = defaultpath;
}
else
{
document.location.href = filterpath + "?" + parameter + "=" + selection;
}
}
  • Line 3: Adding the onchange event allows you to provide an action if the value in the dropdown changes.  I decided to handle this in an externally stored Javascript function called HandleFilterSelection so that I could reuse it easily.
  • Lines 4-11: This xsl:choose lets me alter the prompt based on whether there is currently a filter in place or not.
  • Lines 18-19: This code lets me test to eliminate duplicate values.  This works because I have the list items sorted in descending order by Publish Date.
  • Lines 22-24: If the value is the currently selected value (i.e., it is driving the current filter on the page), this code lets me set it as the selection in the dropdown.
  • Lines 26-28: Unless you specifically set the value that will be returned for the selection, it’s an unpredictable number.  By setting it to the actual text of the selection, we can ensure the it is both recognizable and unique.

UPDATE 2009-05-01 – As a response to Patrick’s question below (It’s hard to include code in a comment.):

In my example, the HandleFilterSelection JavaScript was stored externally from the page because I used it in many places.  (I usually create a Document Library in the root site of the Site Collection called JavaScript to store .js files. I then include them in the pages where I want to use them by adding a <script src=”blah.js”> into the page.)

You can have the onchange event for the select do anything you want.  For example, I often just call the same page with a Query String parameter, like in the code snippet below:

<select name="SelectFluid" size="1">
<xsl:attribute name="onchange">
document.location =
&apos;<xsl:value-of select="$URL"/>&apos; +
&apos;?F=&apos; + this.options[selectedIndex].value;
</xsl:attribute>

To have this work, declare a parameter in the ParameterBindings section for the URL server variable (see my post entitled Data View Web Part Parameters Based on Server Variables for more on using IIS server variables):

<ParameterBinding Name="URL" Location="ServerVariable(URL)" DefaultValue=""/>

and then declare the parameter at the start of your XSL:

<xsl:stylesheet [...]>
<xsl:output method="html" indent="no"/>
<xsl:param name="URL"/>

Parsing Dates Into Archive Buckets in a Calculated Column in SharePoint

I needed to put sets of news articles into buckets in a list so that I could allow users to filter based on the time period in which the articles were published.  To do this, I created a calculated column as a Site Column (for reusability).

Column name: Archive Period

Calculation: =IF([Publish Date]<([Today]-365),”Year” & TEXT(YEAR([Publish Date]),”####”),IF([Publish Date]>0,TEXT(29*MONTH([Publish Date]),”mmmm”)&” “&YEAR([Publish Date]),”Publish Date not set.”))

This formula returns a value like “September 2007” (when the Publish Date is within the last 365 days) or “Year 2006” (when the Publish Date is more than 365 days ago) which is used to drive the population of the archive views.  (We decided to set up a Publish Date column that could be managed separately from the Created Date or Modified Date.)

SharePoint will not allow you to use the Today column in your calculation.  The way to get this to work is to add your own column to the list you are working with called Today.  The type of column for your Today column is basically irrelevant.  This tricks SharePoint because it “thinks” that you are using your own column.  Once you have your calculated column’s formula set up correctly, delete your column called Today and all will work as you wanted.  Keep in mind that any time you want to edit the calculated column, you will need to add back your “fake” Today column.

Note also that Excel is a great place to build up these formulas so that you can take advantage of the contextual help, etc.  See this post.

Technorati tags: ,

Happy New Year, and Back to Work!

It’s been a few quiet months here on my blog, as I have been hunkered down, knee deep in XSL and custom SharePoint pages for a client project.  All of that work has given me some insights on how those mysterious aspx pages that SharePoint generates actually work, and I thought it would be a good idea to do a series of posts on those mechanics.

One of the key things that I’ve realized is that nothing that SharePoint generates for you is inviolate: it’s just code, and you can make any changes that you’d like.  That said, there are certain minimum structures that SharePoint looks for.  (I won’t go into that here, but check out Heather Solomon’s information on minimal master pages, etc.)

There are many things that you might want to accomplish that SharePoint just doesn’t give you a way to do from the interface, either in SharePoint itself, or even in SharePoint Designer.  Most of the standard Web Part parameters are exposed in those interfaces, but there are even some of those that you might want to tweak in code, and if you find that the default Web Parts aren’t doing it for you, you can create your own, or utilize my favorite tool: the Data View Web Part (DVWP).

The bottom line is that while at first glance it’s all a mystery, like most development arenas once you "get it", you can do pretty much whatever you want to do.

Next up: High Level Page Structure.

Office 2007 Service Pack 1 (SP1)

I know that everyone and their br/m/other is going to post about this, but Office 2007 SP1 is now available.  I’m downloading it as I type, hoping that it will fix some of the small annoyances.  (Nothing major, really, just things I’ve learned to work around.)

You can download it here.

Technorati tags: ,