Customizing the Context Menu of Document Library Items
Each document in a document library has a context menu with items such as Check In, Check Out, View Properties, Edit Properties, and others. This menu is created by the AddListMenuItems JavaScript function of the Ows.js file located in the path, C:"Program Files"Common Files"Microsoft Shared"web server extensions"60"TEMPLATE"LAYOUTS"1033. The function starts as shown in the following example.
function AddListMenuItems(m, ctx)
{
if (typeof(Custom_AddListMenuItems) != "undefined")
{
if (Custom_AddListMenuItems(m, ctx))
return;
}
// ...
}
This code checks whether another function named Custom_AddListMenuItems exists, and if it does, it calls it. That function is not defined by Windows SharePoint Services itself but is a function that you can write. The function serves as an injection point to add your own menu items to the document's standard context menu. If the function returns a value of true, the standard AddListMenuItems exits immediately; otherwise, it adds the default items. Here is an example implementation that adds a new item called "Say hello" and a separator line. The new item command item shows a greeting message when clicked.
function Custom_AddDocLibMenuItems(m, ctx)
{
CAMOpt(m, 'Say hello', 'alert("Hello there!");
', '/images/greeting.gif');
CAMSep(m);
return false;
}
As you see, you can add a new item by calling CAMOpt, which takes as input the target menu (received as a parameter by the Custom_AddDocLibMenuItems function), the name of the item, the JavaScript that runs when the item is clicked, and the URL of an image shown to the left of the item. CAMSep adds the separator line.
This example is simple to write and understand but is not realistic. You typically need to add new commands according to a number of rules and conditions that make up your business logic. For example, some commands may be available only to picture documents; others may be available only if the item is not checked out or according to the current user's roles.
You could also retrieve some of this information from the JavaScript code, by using DHTML DOC to read them directly from the page's HTML, or from the ctx parameter that represents the context. However, in more complex cases, you must retrieve the list of available commands from the server, because only there you can run your business logic and perhaps get the commands from a custom database. Typically, you want to do this if you are implementing a workflow solution where each document has its own process state, with commands associated to it.
The solution for this situation is to have the Custom_AddDocLibMenuItems dynamically call a custom ASP.NET page. This page takes the ID of the document library and the specific item on the query string, and returns an XML string containing all the information for the commands available for that particular document. These commands are available according to the document's process status (or some other custom business logic). The returned XML may be something like the following.
<?xml version="1.0" encoding="UTF-8" ?>
<Commands>
<Command>
<Name><![CDATA[Say hello]]></Name>
<ImageUrl><![CDATA[/images/greeting.gif]]></ImageUrl>
<Script><![CDATA[alert('Hello there');]]></Script>
</Command>
...other commands...
</Commands>
The sample page that generates this XML can return either one or two commands:
· If the document is an image (its FieldType attribute is "GIF", "BMP", "JPG" or "PNG"), it returns a command that opens the file in a secondary browser window, without toolbars, menu bars, and status bar.
· For any type of document, it returns a command that, when clicked, runs a search for that document's title on the Google search service.
In reality, you could do both these things directly from the JavaScript function, but this is just an example to show how to write and call server-side logic from the client, for each document's context menu. The following code example shows the sample page's Load event handler.
SPWeb web = SPControl.GetContextWeb(this.Context);
Guid listID = new Guid(this.Request.Params["ListID"]);
int itemID = int.Parse(this.Request.Params["ItemID"]);
SPListItem item = web.Lists[listID].Items.GetItemById(itemID);
string fileUrl = (web.Url + "/" + item.File.Url);
string fileName = item["Name"].ToString();
this.Response.ClearHeaders();
this.Response.ClearContent();
this.Response.Cache.SetCacheability(HttpCacheability.NoCache);
this.Response.AddHeader("Content-type", "text/xml" );
string cmdPattern = @"<Command>
<Name><![CDATA[{0}]]></Name>
<ImageUrl><![CDATA[{1}]]></ImageUrl>
<Script><![CDATA[{2}]]></Script>
</Command>";
this.Response.Write(@"<?xml version=""1.0"" encoding=""UTF-8"" ?>");
this.Response.Write("<Commands>");
string fileType = item["File_x0020_Type"].ToString().ToUpper();
if ( fileType == "BMP" || fileType == "GIF" ||
fileType == "JPG" || fileType == "PNG" )
{
string jsOpenWin = "window.open('" + fileUrl +
"', '', 'menubar=no,toolbar=no,status=no,scrollbars=yes,resizable=yes');";
this.Response.Write(string.Format(cmdPattern, "View in new window",
Page.ResolveUrl("~/images/preview.gif"), jsOpenWin));
}
string jsSearch = "location.href='http://www.google.com/search?q=" +
fileName + "';";
this.Response.Write(string.Format(cmdPattern, "Search on the web",
Page.ResolveUrl("~/images/search.gif"), jsSearch));
this.Response.Write("</Commands>");
this.Response.End();
At this point, Custom_AddDocLibMenuItems is written as a generic function that uses the XMLHTTP Microsoft ActiveX object to send a request to the custom ASP.NET page. The function passes the current list and document IDs to the query string and then parses the returned XML. For each <Command> element it finds, it adds a new menu item with the specified name, image, and JavaScript URL, as shown in the following example.
<script language="javascript">
function Custom_AddDocLibMenuItems(m, ctx)
{
var request;
var url = ctx.HttpRoot +
"/_layouts/CustomMenuItems/GetCommands.aspx?ListID=" +
ctx.listName + "&ItemID=" + currentItemID + "&DateTime=" + Date();
if ( window.XMLHttpRequest )
{
request = new XMLHttpRequest();
request.open("GET", url, false);
req.send(null);
}
else if ( window.ActiveXObject )
{
request = new ActiveXObject("Microsoft.XMLHTTP");
if ( request )
{
request.open("GET", url, false);
request.send();
}
}
if ( request )
{
var commands = request.responseXML.getElementsByTagName("Command");
// for each command found in the returned XML, extract the name,
// image Url and script, and a new menu item with these properties
for ( var i = 0; i < commands.length; i++ )
{
var cmdName = commands[i].getElementsByTagName(
"Name")[0].firstChild.nodeValue;
var imageUrl = commands[i].getElementsByTagName(
"ImageUrl")[0].firstChild.nodeValue;
var js = commands[i].getElementsByTagName(
"Script")[0].firstChild.nodeValue;
CAMOpt(m, cmdName, js, imageUrl);
}
// if at least one command was actually added, add a separator
if ( commands.length > 0 )
CAMSep(m);
// returning false makes SharePoint render the rest of the
standard menu
return false;
}
}
</script>
Notice that the function appends the current date and time to the query string of the GetCommands.aspx page that is called. This is done so that each request is different from a previous one, to avoid caching of the response XML. This is necessary if you are implementing a workflow solution, and a different user may change the document's state after you load the document library's page. If you consider that the Custom_AddDocLibMenuItems function is called every time the drop-down menu pops up, this trick allows you to retrieve the commands to the real current document state, without refreshing the whole page. Figure 3 shows the customized menu.
Figure 3. The new items for the document's context menu
In this sample implementation, GetCommands.aspx returns commands with simple JavaScript code associated to them. However, in a real workflow, you typically return JavaScript that executes another XMLHTTP request to a page that actually performs some server-side action on the clicked document.
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步