Customizing the Shortcut Menu for List Items

This programming task shows how to add a command to the shortcut menu that appears when you right-click a list item. The example adds to document libraries a Check Out & Save command that checks out the selected file and opens the Save As dialog box.

Note  The check out and save operation implemented in this example is not an atomic operation. If the user cancels saving changes, the document remains checked out.

This task involves creating a custom Microsoft JScript file that contains the logic for the command, which is specified by a CustomJSUrl attribute within the ONET.XML file of the site definition.

To include this command in all document libraries created within a site, open ONET.XML in Local_Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\TEMPLATE\1033\SITE_DEFINITION_NAME\XML, and add a CustomJSUrl attribute within the opening Project element, as follows:

<Project Title="Team Web Site" ListDir="Lists" xmlns:ows="Microsoft SharePoint"
   CustomJSUrl="/_layouts/[%=System.Threading.Thread.CurrentThread.CurrentUICulture.LCID%]/custom_ows.js">

Specifying the CustomJSUrl attribute makes the code in the custom JScript file available throughout a site that is created from the site definition. In this example, the custom file is named Custom_ows.js.

Warning  It is required that you create a custom site definition by copying an existing site definition, rather than modifying the original ONET.XML file installed with Windows SharePoint Services. Changes that you make to the originally installed file may be overwritten when you install updates or service packs for Windows SharePoint Services, or when you upgrade an installation to the next product version. For information on creating a custom site definition, see Creating a Site Definition from an Existing Definition.

The code that actually draws the shortcut menu is contained in the OWS.JS file, but you can override functions in this file to add, change, or remove the functionality of the existing menu commands. To find the specific function to customize to suit your needs, trace the path of function calls from the existing CreateMenu function in this file.

Note  When making customizations, you should minimize changes to OWS.JS and instead implement a custom .js file as described in this task. Changes to OWS.JS affect all sites on the server and will be at risk of being lost during an update such as through service packs or patches.

To add a custom Check Out & Save command to the shortcut menu, you will override the AddCheckinCheckoutMenuItem function in OWS.JS by defining a new function of the same name within a custom JavaScript file (Custom_ows.js).

Create a file named Custom_ows.js in the Local_Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\TEMPLATE\LAYOUTS\1033 directory with the following function, which displays either Check In or both Check Out and Check Out & Save on the shortcut menu, depending on whether the file is checked out:

function AddCheckinCheckoutMenuItem(m, ctx, url)
{
    if (currentItemCheckedOutUserId == null)
        currentItemCheckedOutUserId = itemTable.COUId;
    if (currentItemCheckedOutUserId != "")
    {
        strDisplayText = L_Checkin_Text;
        strAction = "NavigateToCheckinAspx('" + ctx.HttpRoot + "', 'FileName=" + url + "')";
        strImagePath = ctx.imagesPath + "checkin.gif";
        CAMOpt(m, strDisplayText, strAction, strImagePath);
    }
    else
    {
        strDisplayText = L_Checkout_Text;
        strAction = "NavigateToCheckinAspx('" + ctx.HttpRoot + "', 'FileName=" + url + "&Checkout=true')";
        strImagePath = ctx.imagesPath + "checkout.gif";
        CAMOpt(m, strDisplayText, strAction, strImagePath);
        strAction = "CheckOutAndSave('" + ctx.HttpRoot + "', 'FileName=" + url + "&Checkout=true')";
        CAMOpt(m, "Check Out & Save", strAction, strImagePath);
        CAMSep(m);
    }
}

The second if clause draws the menu for when the file is already checked out, and the else clause draws the menu for when it is not checked out.

When a user clicks Check Out & Save on the shortcut menu, the following method is called:

function CheckOutAndSave(strHttpRoot, strArgs)
{
    window.onfocus = RefreshOnNextFocus;
    SubmitFormPost(strHttpRoot + "/_layouts/" + L_Language_Text +
        "/CheckSave.aspx?" + strArgs + "&Source=" + GetSource());
}

This method updates the window to show that the file is checked out. The method also sends the file name to an .aspx page that checks out the file and opens the Save As dialog box.

Create a file named CheckSave.aspx in the Local_Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\TEMPLATE\LAYOUTS\1033 directory with the following contents:

<%@ Page language="C#" EnableViewStateMac="false" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls"
  Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral,
  PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>

<script >
void Page_Load()
{
    SPWeb web = SPControl.GetContextWeb(Context);
    string strPath = Request.QueryString["FileName"];
    SPFile file=web.GetFile(strPath);

    if ((file.Exists) && (file.CheckOutStatus==Microsoft.SharePoint.SPFile.SPCheckOutStatus.None))
    {
        Response.Clear();
        file.CheckOut();
        Response.AddHeader("Content-Disposition", "attachment; filename=" + file.Name);
        Response.AddHeader ("Content-Length", file.Length.ToString());
        Response.ContentType = "application/octet-stream";
        Response.BinaryWrite(file.OpenBinary());
    }
    else
    {
        Response.Write("The file does not exist or is already checked out.");
    }
}
</script>

Note  You can obtain the PublicKeyToken value for the current Windows SharePoint Services deployment from the default.aspx file in the Local_Drive:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\60\TEMPLATE\LCID(1033 in English)\STS folder, or from information provided for the Microsoft.SharePoint assembly at Local_Drive:\WINDOWS|WINNT\assembly in Windows Explorer.

This page first checks to see that the file exists and that it is not currently checked out. It then checks out the file and returns the contents to the browser. Setting Response.ContentType to "application/octet-stream" causes the browser to open the Save As dialog box.

Reset Internet Information Services (IIS), create a site based on the site definition you modified, and create a document library to test the new functionality.

With some minor changes, it is possible to make this menu appear only in document libraries based on a specified custom list definition, rather than in all document libraries.

Create a custom list definition for document libraries (see Creating a List Definition), and take note of the value that you assign to the Type attribute of the ListTemplate element (in this example, 555). Modify the AddCheckinCheckoutMenuItem function in Custom_ows.js as follows:

function AddCheckinCheckoutMenuItem(m, ctx, url)
{
    if (currentItemCheckedOutUserId == null)
        currentItemCheckedOutUserId = itemTable.COUId;

    if (currentItemCheckedOutUserId != "")
    {
        strDisplayText = L_Checkin_Text;
        strAction = "NavigateToCheckinAspx('" + ctx.HttpRoot + "', 'FileName=" + url + "')";
        strImagePath = ctx.imagesPath + "checkin.gif";
        CAMOpt(m, strDisplayText, strAction, strImagePath);
    }
    else
    {
        strDisplayText = L_Checkout_Text;
        strAction = "NavigateToCheckinAspx('" + ctx.HttpRoot + "', 'FileName=" + url + "&Checkout=true')";
        strImagePath = ctx.imagesPath + "checkout.gif";
        CAMOpt(m, strDisplayText, strAction, strImagePath);

        if (ctx.listTemplate == 555)
        {
            strAction = "CheckOutAndSave('" + ctx.HttpRoot + "', 'FileName=" + url + "&Checkout=true')";
            CAMOpt(m, "Check Out & Save", strAction, strImagePath);
            CAMSep(m);
        }
    }
}

Notice that the value you assign to the ID attribute for the custom list template is used in the line if (ctx.listTemplate == 555), which is where the ID of the list definition is checked. The Check Out & Save command will appear only on shortcut menus for document libraries that are based on this list definition.