Customizing SharePoint Context Menus
Introduction
Drop-down menus in Windows SharePoint Services and SharePoint Portal Server 2003 enable actions that relate to a specific document in a document library to be viewed and invoked. This article shows how these document context menus can be extended to add custom menu items. The document first explains how SharePoint document library context menus work, and then demonstrates how custom menu items can be added.
The Business Problem
Windows SharePoint Services (WSS) document libraries provide a location to store and share files and documents. The WSS user interface provides a context sensitive drop-down menu for each item stored in a document library (Figure 1). A common requirement is the ability to customise this menu to add new actions. For example you might wish to add an option to enable a document to be copied or moved to another location or emailed to a colleague.
Figure 1 Document context menu in a SharePoint Document Library
The solution and sample code presented in this article shows how a custom menu item can be created that sends an email link to the relevant document to another user.
Solution Overview
The WSS document context menu is generated by client-side Javascript. The script to display these menus is located in a file called ows.js in the folder \Program Files\Common Files\Microsoft Shared\web server extensions\60\TEMPLATE\LAYOUTS\1033 on the SharePoint server. The AddDocLibMenuItems function in ows.js is responsible for generating the drop-down menus. The AddDocLibMenuItems implementation provides a hook through which additional menu items can be added to the context menu. The first few lines of this function read:
function AddDocLibMenuItems(m, ctx)
{
if (typeof(Custom_AddDocLibMenuItems) != “undefined”)
{
if (Custom_AddDocLibMenuItems(m, ctx))
return;
}
..etc..
This piece of code is checking whether a function called Custom_AddDocLibMenuItems is defined, and if it is then calling it. By implementing this function in a page containing a document library web part, we can extend the context menu, adding our own menu items.
The Custom Menu Items Web Part
So, how can we add a custom piece of JavaScript to a SharePoint page? We need to make sure that the technique we use is configurable and flexible, and that we don’t change any of the built-in script or features of SharePoint so that our implementation is not overwritten by any SharePoint upgrades or service packs that may be deployed in the future.
Fortunately SharePoint provides a convenient mechanism for doing this – the Content Editor Web Part. The Content Editor Web Part enables custom HTML and script to be added to a page and delivered to the browser.
Adding the Web Part to a Page
In SharePoint, navigate to a page with a document library web part on it, or add one to an existing page.
On the Modify Shared Page menu, point to Add Web Parts and click on Browse.
Drag the Content Editor Web Part from the tool pane onto the page, then click Open Tool Pane link in the web part.
In the Layout section clear the Visible on Page checkbox. This means the web part is not visible to the end-user, but the script we add to the web part is still delivered to the client browser. In the page design view, you can still see the web part, but it is marked as hidden. If you wish you can also change the title of the web part in the Appearance section of the tool pane.
Figure 2 Hidden Web Part in Design View
From the tool pane, open the Source Editor and insert the following script:
<script language="javascript">
function Custom_AddDocLibMenuItems(m, ctx)
{
var strDisplayText = "Say Hello World!";
var strAction = "alert('Hello World')";
var strImagePath = "";
// Add our new menu item
CAMOpt(m, strDisplayText, strAction, strImagePath);
// add a separator to the menu
CAMSep(m);
// false means that the standard menu items should also be rendered
return false;
}
</script>
Click Save in the Source Editor, and then click OK in the tool pane.
Now test the web part by opening a document library drop-down menu on the same page. You should see the new menu item at the top of the menu with a separator bar splitting it from the rest of the menu.
Figure 3 Drop-down menu with Hello World item added
How It Works
The Custom_ AddDocLibMenuItems function takes two parameters. The first parameter, called m, represents the menu object itself; the second parameter, ctx, provides HTTP context information about the web request.
Adding a menu item to the menu requires just one function call:
CAMOpt(m, strDisplayText, strAction, strImagePath);
The CAMOpt function takes four parameters: the menu object to add the new item to, the display text of the menu item, the javascript action to perform when the item is clicked and a path to an image file to associate with the item.
A call to the CAMSep function adds the separator bar to the menu. Both these functions are defined in the menu.js file on the SharePoint server.
Finally, the function returns false to the caller. This makes sure the standard menu items are also added to the menu; returning true indicates that these items should not be added.
Debugging the Web Part
To debug the web part, insert a debugger statement into the web part JavaScript:
debugger;
Provided a suitable debugger (such as Visual Studio.NET or the Microsoft Script Debugger) is installed, this statement causes Internet Explorer to break into the script when it is run, and offer the opportunity to start debugging.
Note: By default Internet Explorer disables script debugging. To make sure script debugging is enabled, open the Internet Options dialog from the Tools menu, and on the Advanced tab clear the Disable script debugging check box.
Once in the debugger, you can use the watch window to examine the variables that are available. Interesting variables to examine are m – the menu object, ctx which contains HTTP context information and itemTable which contains information about the list item the menu is associated with.
The Send Mail Web Part
Now we have figured out the principles of customising the drop down menus, the next step is to have them do something useful! The following script adds a menu item that sends an email link to the relevant document. It works by parsing the document URL out of the itemTable object and creating an action that instructs Internet Explorer to start a new mail message.
To use create this web part, simply follow the same steps that we used to create the Hello World menu item, using this script instead:
<script language="javascript">
function Custom_AddDocLibMenuItems(m, ctx)
{
var strDisplayText = "Send Link By Email...";
var strAction;
var strImagePath = "";
// parse the URL out of the itemTable
var URL = "";
var index = itemTable.innerHTML.indexOf("href=");
if (index > 0)
{
var str = itemTable.innerHTML.substr(index + 6);
index = str.indexOf('"');
if (index > 0)
{
URL = str.substr(0, index);
}
}
if (URL != "")
{
strAction = 'window.navigate("mailto:%20?subject=Take a look at this document...&body=<' + URL + '>")';
// Add menu item
CAMOpt(m, strDisplayText, strAction, strImagePath);
// add a separator to the menu
CAMSep(m);
}
return false;
}
</script>
Clicking the custom menu item opens a new email message with the URL of the document in the body of the message.
Code Samples
Attached with this article are dashboard web parts (.dwp files) for the two samples discussed here. To use them, first unzip them to disk, then go to the Modify Shared Page menu, point to Add Web Parts and click on Import. This adds the custom web parts to the web part gallery so that they can be added to a page.
Conclusion
This article has demonstrated one way in which SharePoint Document Library drop-down menus can be augmented with custom menu items. An alternative technique is also described in the SharePoint Products and Technologies SDK.
One final thing to note is that the technique described here is not limited to Document Library menus - custom menu items can be added to any list in SharePoint 2003 thanks to a similar hook called Custom_AddListMenuItems.
Comments
- Anonymous
July 20, 2004
Fantastic article Mark...well done!!
I have been asked to do a contract with SharePoint and the ows.js file - i have done a tiny bit of programming (in Access) and S.Point implementation - due to your article i think that i could give this new contract a go...WELL DONE!!
stevehowlett10@hotmail.com - Anonymous
July 22, 2004
Hi Marc. Great stuff! I've been using your example plus the one in the SDK to try to add my own.
I don't want to implement my extension via the ows.js file because I need to add it to only one existing doc lib.
However, it looks like the needs of my extension uses both a combination of your implementation via a Web Part, and the SDK example to call an .aspx page. My extension needs to use the Microsoft.SharePoint.Portal.SiteData namespace to work with Area classes to send the selected document to a particular Topic.
If you could offer me any guidance or tips for this scenario I'd appreciate it. - Anonymous
July 26, 2004
Hi Eric,
The scenario you describe is perfectly feasible, and one I have used myself in previous projects. What I did was create a custom .aspx page on the SharePoint server and configure it to accept a number of input params as a query string. Then I simply configured the web part so that a click on the custom menu item caused IE to navigate to my custom page. I have used this technique in the past to provide a facility to copy & move documents between different document libraries. - Anonymous
July 26, 2004
The comment has been removed - Anonymous
July 26, 2004
Thanks for the feedback Mark. I've went ahead with my project, but have hit a wall. If you could review my post ("Problems with custom Context Menu item", dated July 23) in the microsoft.public.sharepoint.portalserver.development newsgroup, I'd appreciate it. - Anonymous
July 29, 2004
Hi Mark, this is very interesting, however how would you go about installing/deploying such a solution? We want to customise the menu but we don't really want the client to have to manually enter this information. We would like to use a script or msi to install this.
Many thanks John - Anonymous
July 30, 2004
John,
YOu can export your completed web part to a dwp file, then import it onto your production servers. Does that help? - Anonymous
August 01, 2004
Hi Mark,
How can we remove default context menu? so for your example we only display the "Send email" context ?
I also wonder if we can display different context based on value on specified coloumn. For example, if the value in coloumn status is "OK" then it will display "Send email" otherwise it will display "Reject it".
Thanks,
Riwut - Anonymous
August 02, 2004
To remove the default menu you simply need to return true from your custom menu routine. Details are in the article.
I am sure you could also display different menu items. The itemTable object would be the one to examine in this case to determine if the property you want to make the decision about is available client-side. - Anonymous
August 02, 2004
The comment has been removed - Anonymous
August 03, 2004
Sorry Kaush, I don't understand your question. However, why not try posting your query on http://msdn.microsoft.com/newsgroups/default.aspx?dg=microsoft.public.sharepoint.windowsservices&lang=en&cr=US ? Someone there may be able to help you. - Anonymous
August 04, 2004
Hi Mark,
Your example is very helpful. I'm trying to implement a "move documents between document libraries" functionality by adding a move item to the menu. I read you have done that before. Could you give me any ideas on how to do it?
Thanks. - Anonymous
August 05, 2004
Hi Joe,
To perform a move between libraries you will need some server-side code to manipulate the WSS API. The basic technique is this:
- Create an ASPX page that performs the document move as you require it, and accepts a couple of input parameters (the document to move, and the library to move to) as either query string or form fields. Store the page in the LAYOUTS folder. There is some info in the WSS SDK about creating custom ASPX pages.
- In your custom menu, parse out the document name & location from the itemTable object and use this to cretae the parameters required by your ASPX page.
- Then when the menu item is clicked either perform a GET or POST against your custom page to perform the file move. - Anonymous
August 05, 2004
Thanks Mark, for the info. One more question - do you know if we can add a menu item to the menu on the document library page itself? In your example, you were adding a menu item to the document library which is placed as a web part on a site. Our requirement is to add the menu item on the document library page (AllItems.aspx) itself.
Thanks. - Anonymous
August 09, 2004
Mark, Great article. Works great. Have a question? Send Link by Email works great for documents but not for folders, when I send out a email for folders, in the body i have "javascript:SubmitFormPost()", have you figured out a workaround for this? Any suggestions? Thank you. - Anonymous
August 10, 2004
Julio,
I haven't investigated this, but I am guessing that the itemTable array is structured differently for folders. To try and fix this you will need to run the code with the script debugger and examine the itemTable variable to identify how the folder path should be parsed out. - Anonymous
August 10, 2004
Hi Joe, The article in the SharePoint SDK (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/spptsdk/html/tsptAddingContextMenu.asp) describes a technique for doing this. - Anonymous
August 10, 2004
Thanks Mark, for the info. Looks like we have to modify built-in sharepoint files in order to do that. May be we should create a web part that redirects the user to the move aspx page or something...
I have one more question though..what do you use for actually moving the file. SPFile MoveTo method? I'd appreciate if you could provide a sample code of the move functionality you developed.
Thanks much. - Anonymous
August 10, 2004
Sorry..one more question. I was just trying to test the procedure you described above to add the content editor web part to a site where there is a document library web part and I don't see the standard drop down menu for the file in the web part.
I can see the drop-down menu for the file if I go to the document library page itself, but not if it is a web part on the site home page. Please let me know if you have any idea why.
Thanks again. - Anonymous
August 10, 2004
Mark, Thanks again for the pointer re: sending out a email link for folder. I took your suggestion and used the debugger and figured out how to do this. In fact, I solved it for even nested folders any level deep. Thank you. - Anonymous
February 16, 2005
Bei Mark Kruger habe ich gerade nochmal einen Hinweis auf einen Artikel von Mark Bower gefunden, in dem beschrieben wird, wie man die Kontextmenus auf einer Windowe SharePoint Site anpassen kann. - Anonymous
February 16, 2005
Bei Mark Kruger habe ich gerade nochmal einen Hinweis auf einen Artikel von Mark Bower gefunden, in dem beschrieben wird, wie man die Kontextmenus auf einer Windowe SharePoint Site anpassen kann. - Anonymous
July 19, 2005
I have a web part to copy a document (files only not folders) from one document library to another doc library. I have customize "SharePoint Context Menus" and added a "copy" menu. If I select any file, it works but if there is a folder inside a document library, it doesn't.
So how can I find out whether a selected item is a folder/file? And if it is a folder, I do not want to display "copy" item in the SharePoint Context Menu List.
Thanks in advance and here is code of what I have done so far.
-----------------------------------------------
<script language="javascript">
function Custom_AddDocLibMenuItems(m, ctx)
{
var strDisplayText = "Copy";
var strAction;
var strImagePath = "";
var HOST_NAME;
var fileDirPath;
var fileOrDir_Name;
var dotIndex;
HOST_NAME = window.location.hostname
fileDirPath = itemTable.ServerUrl;
//alert("ctx.HttpRoot: " + ctx.HttpRoot);
fileOrDir_Name = fileDirPath.substring(fileDirPath.lastIndexOf('/')+1)
dotIndex = fileOrDir_Name.indexOf('.');
if (fileDirPath != "" && dotIndex != -1)
{
strAction = 'window.navigate("http://localhost/sites/Site1/default.aspx?query='+fileDirPath+'&host='+HOST_NAME+'")';
// Add menu item
CAMOpt(m, strDisplayText, strAction, strImagePath);
// add a separator to the menu
CAMSep(m);
}
return false; // this enables the rest of the menu items to be rendered.
}
</script>
-----------------------------------------------
PJ - Anonymous
July 20, 2005
PJ,
Thanks for sharing you code with everyone.
If the information about folder vs. file is available you will likely find it in the itemTable object. I'd suggest you examine it with your jscript debugger to determine what information you can extract.
The other option is to enable copies of folders of course and write a routine to do the copy. - Anonymous
July 28, 2005
The comment has been removed - Anonymous
August 10, 2005
Did you know that you can go into MS Frontpage 2003, add a webpart zone, and then a Content Editor webpart. Then you add the code to send email and now you can send the link via email from the DOC library, or List. Hope this helps.
Justin - Anonymous
September 12, 2005
Hello, I am hoping this is still read...
Thats a great tip its working for shared docs, I have a question how would I get this to work with a list (i have added the web part using frontpage to the list but it doesnt work) :( - Anonymous
September 12, 2005
Russell, to work with lists you need to rename your function to Custom_AddListMenuItems(). - Anonymous
September 12, 2005
Thanks superb :) i have been lokoing for this for ages, last question, is it possible to apply this to all lists/doc libraries in one go? or do I have to add the webpart to each one? - Anonymous
September 12, 2005
This technique enables you to customize menus one at a time. To apply the technique to all the lists/doc libs use the technique described in the MSDN article I reference in the Conclusion section above. - Anonymous
June 04, 2006
&nbsp;&nbsp;&nbsp;Очень интересной возможностью, представленной в SharePoint Portal Server 2003 является... - Anonymous
June 29, 2006
I have been mulling over this for a long time so I thought I'd start a post and see where it went, and...