Document title in SharePoint’s “ECB” dropdown menu

Have you ever wondered why the SharePoint team decided to show only filename in dropdown menus, but not the title of the document? So when you save your file with an unreadable filename, it is displayed in your list and looks something like this (Historical note: it was not the case in SharePoint 2001. They changed it in SPPS2003 and in 2007 versions. 2010. has it fixed):

You can, of course, modify the “All Items” view and add the “Title” column, but it never has a link to the document, nor has it the fancy drop-down for editing (see the column “Title” in the picture).

So, I decided to dig into CAML schemas and to create a field which would display the title of the document and have the dropdown menu. To achieve that, one can use “computed fields” – fields which do not actually represent data editable by the user, but are only used for presentational purposes. Hence, one only has to define the DisplayPattern of that field.
There are two fields already built into SharePoint – the _EditMenuTableStart and _EditMenuTableEnd, which build the dropdown menu contents. What I had to add, was generation of the readable content. The most important part of the display pattern is this:

<IfEqual>
  <Expr1><LookupColumn Name="Title" /></Expr1>
 <Expr2></Expr2>
<Then>
     <Field Name="FileLeafRef" />
 </Then>
 <Else>
     <Column HTMLEncode="FALSE" Name="Title" Default="(no title)" />
  </Else>
</IfEqual>

It compares the value of the Title column to an empty string. If this is the case (you have uploaded a document with no title or created a folder using Explorer view), it just shows FileLeafRef – the filename. Otherwise, it displays the value of the title field.

In my case I had an existing document library which I wanted to “fix”. Hence, I created a PowerShell script, which adds my field to the library. I used “AddFieldAsXML()” method of SPList object to inject my CAML code into sharepoint.

Now it looks like this:

You can dowload the whole script here: http://tips.naivist.net/wp-content/CreateTitleField1033.ps1_.txt Rename it to .ps1 and run it .\CreateTitleField1033.ps1 -url http://yourserver/sites/somesite/someweb -ListName "Your list". Then modify the view settings to display the field.

If you are developing your own list defintion, you can use the particular fragment in schema.xml and have your field defined in a regular fashion.

param(
  [string] $url      =  "",
  [string] $ListName = ""
)

$sharepoint = [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$site=[Microsoft.Sharepoint.SPSite]($url);
$web=$site.openweb();
$list= $web.lists[$ListName];

$schema =@"
    <Field ID="{E2ABF8D3-6435-4773-A3D6-67508FEB7CF5}" ReadOnly="TRUE" 
             Type="Computed" 
             Name="KRItemLinkTitleDropdown" 
             DisplayName="Title" 
             DisplayNameSrcField="Title"
             AuthoringInfo="(dropdown displaying the title field)"
             EnableLookup="TRUE" 
             SourceID="http://schemas.microsoft.com/sharepoint/v3"
             StaticName="KRItemLinkTitleDropdown" FromBaseType="TRUE" ClassInfo="Menu">
         <FieldRefs>
          <FieldRef Name="Title" />
          <FieldRef Name="LinkTitleNoMenu" />
          <FieldRef Name="FSObjType" />
        </FieldRefs>
        <DisplayPattern>
           <Field Name="_EditMenuTableStart" />
           <HTML>
           <![CDATA[<A onfocus="OnLink(this)" HREF="]]></HTML>
       <IfEqual>
            <Expr1>
              <LookupColumn Name="FSObjType" />
            </Expr1>
            <Expr2>1</Expr2>
            <Then>
                <FieldSwitch>
                <Expr>
                  <GetVar Name="RecursiveView" />
                </Expr>
                <Case Value="1">
                  <LookupColumn Name="FileLeafRef" HTMLEncode="TRUE" />
                </Case>
                <Default>
                  <SetVar Name="UnencodedFilterLink">
                    <SetVar Name="RootFolder"><HTML>/</HTML>
                      <LookupColumn Name="FileRef" />
                    </SetVar>
                    <SetVar Name="FolderCTID">
                      <FieldSwitch>
                        <Expr>
                          <ListProperty Select="EnableContentTypes" />
                        </Expr>
                        <Case Value="1">
                          <Column Name="ContentTypeId" />
                        </Case>
                      </FieldSwitch>
                    </SetVar>
                    <FilterLink Default="" Paged="FALSE" />
                  </SetVar>
                  <GetVar Name="UnencodedFilterLink" HTMLEncode="TRUE" />
                </Default>
              </FieldSwitch>     
             </Then>
            <Else>
                <Field Name="ServerUrl" URLEncodeAsURL="TRUE" />
            </Else>
            </IfEqual>


       <HTML><![CDATA[" onclick="return DispEx(this,event,']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <ServerProperty Select="HtmlTransform" />
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <ServerProperty Select="HtmlTrAcceptType">
                      <Column Name="File_x0020_Type" />
                    </ServerProperty>
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <ServerProperty Select="HtmlTrHandleUrl">
                      <Column Name="File_x0020_Type" />
                    </ServerProperty>
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <ServerProperty Select="HtmlTrProgId">
                      <Column Name="File_x0020_Type" />
                    </ServerProperty>
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <ListProperty Select="DefaultItemOpen" />
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <MapToControl>
                      <Column Name="HTML_x0020_File_x0020_Type" /><HTML>|</HTML>
                      <Column Name="File_x0020_Type" />
                    </MapToControl>
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <Column Name="HTML_x0020_File_x0020_Type" />
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <ServerProperty Select="GetServerFileRedirect">
                      <Field Name="ServerUrl" /><HTML>|</HTML>
                      <Column Name="HTML_x0020_File_x0020_Type" />
                    </ServerProperty>
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <Column Name="CheckoutUser" />
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <UserID AllowAnonymous="TRUE" />
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <ListProperty Select="ForceCheckout" />
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <Field Name="IsCheckedoutToLocal" />
                  </ScriptQuote><HTML><![CDATA[',']]></HTML>
                  <ScriptQuote NotAddingQuote="TRUE">
                    <Field Name="PermMask" />
                  </ScriptQuote><HTML><![CDATA[')">]]></HTML>
                  <UrlBaseName HTMLEncode="TRUE">
                  </UrlBaseName>
                    <IfEqual>
                    <Expr1>
                      <LookupColumn Name="Title" />
                    </Expr1>
                    <Expr2></Expr2>
                    <Then>
                        <Field Name="FileLeafRef" />
                     </Then>
                    <Else>
                        <Column HTMLEncode="FALSE" Name="Title" Default="(no title)" />
                    </Else>
                    </IfEqual>
                  <IfEqual>
                    <Expr1>
                      <GetVar Name="ShowAccessibleIcon" />
                    </Expr1>
                    <Expr2>1</Expr2>
                    <Then><HTML><![CDATA[<img src="/_layouts/images/blank.gif" class="ms-hidden" border=0 width=1 height=1>]]></HTML>
                    </Then>
                  </IfEqual><HTML><![CDATA[</A>]]></HTML>
                  <IfNew Name="Created_x0020_Date"><HTML><![CDATA[<IMG SRC="/_layouts/1033/images/new.gif" alt="New!">]]></HTML>
                  </IfNew>
                  <Field Name="_EditMenuTableEnd" />
        </DisplayPattern>
      </Field>
"@
$fieldname = $list.fields.AddFieldAsXml($schema);
$list.update();