Using the Current Page URL in the UrlAction of a SharePoint Feature
With the introduction of the feature framework in SharePoint 2007, developers have some great opportunities to customize and enhance nearly everything in SharePoint. One of the things that's quite easy to do with the help of a feature, is to add and/or replace functionality in the web user interface of SharePoint site. This was typically very hard to do (in a nice way) for the previous version of SharePoint (remember having to edit a javascript file to add a menu item in the ECB?).
Let's take the following example of a feature's manifest file:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="{6FCB0F81-2105-4d9f-96BF-C48A19B8E439}"
Title="My Link"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="SettingsMenu">
<UrlAction Url="_layouts/mypage.aspx"/>
</CustomAction>
</Elements>
When activated, the feature will add a menu item to the Settings menu of any SharePoint list or document library. The menu item will have the title My Link, when clicked the user will navigate to the page mypage.aspx in the _layouts folder (the typical place to deploy your custom application pages).
If you build some functionality in the mypage.aspx, in many scenarios this page will need to know from which list the link originated. This can be done by using URL tokens in the UrlAction element:
<UrlAction Url="_layouts/mypage.aspx?listid={ListId}"/>The {ListId} URL token will be automatically replaced with the ID of the list, in which the menu item is shown. In the mypage.aspx, you can retrieve the value of the listid parameter by making use of the QueryString. Once you've got the ID, the object model can be used to get a reference to the SPList instance of that list. According to the documentation on MSDN, the following URL tokens can be used:
- ~site - Web site (SPWeb) relative link.
- ~sitecollection - site collection (SPSite) relative link.
- In addition, you can use the following tokens within a URL:
- {ItemId} - Integer ID that represents the item within a list.
- {ItemUrl} - URL of the item being acted upon. Only work for documents in libraries. [Not functional in Beta 2]
- {ListId} - GUID that represents the list.
- {SiteUrl} - URL of the Web site (SPWeb).
- {RecurrenceId} - Recurrence index. This token is not supported for use in the context menus of list items.
Unfortunately there is no token that will give you the URL of the page on which the feature's link is being displayed. In many cases you want to have that URL to be able to redirect, after you've shown your custom functionality, to the originating page. SharePoint itself uses this technique a lot: in many URL's you'll find the Source parameter:
http://wss.u2ucourse.com/Lists/Links/NewForm.aspx?Source=http%3A%2F%2Fwss%2Eu2ucourse%2Ecom%2Fdefault%2Easpx
The URL above points to the NewForm.aspx for the a Links list. Normally when the user fill's out this form and clicks OK, this page redirects to the default view of the list. Because this link has the Source parameter, when the user clicks OK (or cancel), the page will redirect to the default.aspx instead. You can add the Source parameter to a lot of pages in SharePoint, giving you full control over the redirecting.
So the issue is: we want to include the URL of the originating page in the UrlAction element of the feature's CustomAction, but all we get are a bunch of ID's and some URL's that are not useful for this scenario. As usual peeking in the machine room of SharePoint itself can give you some good ideas to solve this issue. The SharePoint guys themselves sometimes use Javascript functions in the UrlAction, instead of ordinary hyperlinks. Thus with some clever use of Javascript, it's quite easy to solve the problem:
<UrlAction Url="javascript:window.location= '{SiteUrl}/_layouts/mypage.aspx?List={ListId}&Source=' + window.location"/>
The actual link is a Javascript function that will navigate to a specific URL. This URL is a concatenation of the URL of the page to display (including for example the ID of the list as a parameter in the QueryString), and the Source parameter which is dynamically set the current page's URL. Et voila, the constructed link will point to your page, and the redirect will always point to the page you started from.
Extra: this tric can also be used to overcome a bug in SharePoint that causes a URL token of a CustomAction to be replaced only once. So if you have used the ListID token two times in a UrlAction element, only one of the token's will be replaced with the actual ID of the list. The user "FlatEric" (what's in a name?) explains this in the Community Content of the How to: Add Actions to the User Interface article on MSDN.
I found an ugly way to bypass this flaw:
<UrlAction Url="javascript:function process(){var site='{SiteUrl}';var item={ItemId};window.location.href=site+'/Lists/MyList/NewForm.aspx?ID='+item+'&Source='+site+'/Lists/myOtherList/DispForm.aspx?ID='+item;};process();"/>