Chapter 14: Authoring Experience Extensibility

This article is an excerpt from Professional SharePoint 2007 Web Content Management Development: Building Publishing Sites with Office SharePoint Server 2007 by Andrew Connell from Wrox (ISBN 978-0-470-22475-5, copyright Wrox 2008, all rights reserved). No part of these chapters may be reproduced, stored in a retrieval system, or transmitted in any form or by any means—electronic, electrostatic, mechanical, photocopying, recording, or otherwise—without the prior written permission of the publisher, except in the case of brief quotations embodied in critical articles or reviews.

All Web content management systems provide content authors with a user-friendly and easy way to create and manage content within a Web site. The capabilities offered in Microsoft Office SharePoint Server (MOSS) 2007 Publishing sites is no different. Content authors simply need to navigate to the section of the site where they want to add content, authenticate, and create new content using the provided browser interface.

What if this experience is not enough? Thankfully, SharePoint does not stop there. SharePoint, Windows SharePoint Services (WSS) 3.0, at its core is very extensible. Many opportunities exist for extending and replacing the functionality provided out-of-the-box (OOTB) in SharePoint. Thanks to the architecture of SharePoint 3.0, everything that WSS 3.0 has to offer is available to MOSS 2007 and thus, Publishing sites. Previous chapters have touched on the different customization options available to developers in providing a unique experience for content owners, such as page layouts, custom field controls, custom Web Parts, and custom workflows. This chapter takes the authoring experience a bit further and discusses some additional extensibility options available to SharePoint developers to customize the authoring experience.

Contents

  • Customizing SharePoint Navigation with Custom Actions

  • Offline Authoring with Document Converters

  • Edit Model Panel

  • Customizing the HTML Editor Field Control

  • Telerik RadEditor Lite for MOSS

  • Customizing the Page Editing Toolbar

  • Summary

Customizing SharePoint Navigation with Custom Actions

SharePoint has numerous system menus scattered throughout the product, such as the Site Actions menu, the Site Settings page, list pages (new/edit/display) with toolbars, as well as the edit control block (ECB) shown in Figure 14-1 for all list items. The menu structure is based on the concept of actions. Actions are registered to a specific menu within a specific context using WSS 3.0 Features. When a page loads, SharePoint interrogates the internal list of registered actions to get a list of the items that should appear in each menu.

Figure 14-1

Figure 14-1

Thanks to WSS 3.0 and the Features framework it is quite easy to manipulate the SharePoint menus. In fact, Microsoft even used this model to implement the menus. If you have ever been curious about how the Site Settings page is created, take a look at the Site Settings Feature located in the[..]\12\TEMPLATE\FEATURES\SiteSettings folder.

How does customizing SharePoint menus serve as a useful tool for developers in creating a customized authoring experience? The ideal time to modify the menus is when the desired customization does not directly affect the content the user is working on, but rather the overall experience. What if the content authors at one organization are not technically savvy in that they don't know HTML and primarily work within the Office client applications such as Word and Excel? No matter how hard developers try, the Web experience is always a little different than the thick client experience. What if some content management tasks need to be provided as tutorials for organizations with a high rate of turnover in the group that manages content in one section of the site? It is not very efficient to repeatedly have to hold training sessions with the new content authors. In these cases, developers could create some customized tutorials delivered as either a Web experience or an offline experience. Rather than send a bunch of links around to the content authors every time new employees join the company, developers could create a new link on the Site Actions menu that all authenticated users would see, linked to the tutorials, as Figure 14-2 demonstrates.

Figure 14-2

Figure 14-2

Adding items to SharePoint menu, like the Tutorials link at the bottom of the Site Actions menu shown in Figure 14-2, is achieved using Features. The site element <CustomAction /> enables developers to create menu items and specify things such as title, description, image, and even permission rights indicating what users must have in order to keep the menu item from being "security trimmed" from their experience. The element manifest file to create the Tutorials menu item in Figure 14-2 is shown in Listing 14-1.

Listing 14-1: Element manifest file creating a menu item

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="https://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="A4C9FEB8-D867-4045-BC17-083AED73E7E6"
                Location="Microsoft.SharePoint.StandardMenu"
                GroupId="SiteActions"
                Sequence="100"
                ImageUrl="/_layouts/images/lg_ICHLP.gif"
                Title="Tutorials"
                Description="Content author and owner online tutorials.">
    <UrlAction Url="/_layouts/WROX/Tutorials/default.aspx" />
  </CustomAction>
</Elements>

In addition to the <CustomAction /> site element, WSS offers two additional site elements that are used to manipulate the SharePoint menus:

  • <CustomActionGroup /> creates a new group of menu items. For example, it can create a new column of links on the Site Settings page.

  • <HideCustomAction /> is used to hide actions created by other Features.

Offline Authoring with Document Converters

The remainder of the chapter details the different Web authoring extensibility options available in Publishing sites exclusively. However, before moving into Web authoring, let's briefly explore the offline authoring capabilities. Content authors are not limited to just the Web authoring capabilities MOSS 2007 Publishing sites offer. Pages can be created and managed using offline tools such as Office Word 2007 or InfoPath 2007. This capability is facilitated with document converters. Once a document converter is registered with a specified document library, SharePoint monitors the document library for new content. When new content arrives in the document library, it is passed to the registered document converter, which then creates a Web page and stores that page in the appropriate Pages library. This process does not bypass any security or workflow configurations; it simply automates the process of creating or updating an existing page in the Web experience.

Note

Document converters are covered in detail in Chapter 18, "Offline Authoring with Document Converters."

Edit Model Panel

At some point in a Publishing site project, business requirements will dictate that the author's editing experience should be different from that of the display experience. For example, what if some fields on a page need to be edited by the content authors but not shown to people browsing the site? This technique comes in handy when a page needs to have some metadata associated with it at the same time that it would be used in classifying or grouping pages in a Content Query Web Part or for more advanced searching techniques.

The way to provide different editing and display experiences in MOSS 2007 Publishing sites is through the EditModePanel. The EditModePanel, used in page layouts, is an ASP.NET 2.0 composite control in that it can contain child controls. By default, it only renders the controls within the panel when the page is in Edit mode, but this is configurable using the PageDisplayMode property. When the PageDisplayMode property is set to Display, it displays the controls when the page is in Display mode. When the PageDisplayMode property is set to Edit (which it is by default), it displays the controls when the page is in Edit mode.

The EditModePanel is demonstrated in the page layouts included in the Publishing Portal site template—specifically, those associated with the Article Page content type (see Figure 14-3). A gray box is rendered at the bottom of a page containing a field control for a thumbnail image. The intention is to not use this image when viewing the content page but rather only in rollup Web Parts such as the Content Query Web Part as a thumbnail in a list of content.

Figure 14-3

Figure 14-3

To add the EditModePanel to a page layout, either drag it from the SharePoint Controls section in the Toolbox task pane in SharePoint Designer onto the page layout or add the markup in Listing 14-2. In this case, the editor part will display its contents when the page is in Edit mode only.

Listing 14-2: Using an EditModePanel

<PublishingWebControls:EditModePanel  PageDisplayMode="Edit">
  <table cellpadding="10" cellspacing="0" align="center" class="editModePanel">
    <tr>
      <td>
        <PublishingWebControls:RichImageField FieldName="PublishingRollupImage" 
                                               />
      </td>
    </tr>
  </table>
</PublishingWebControls:EditModePanel>

Notice the CSS editModePanel class assigned to the table in Listing 14-2. This CSS class is what gives the EditModePanel the gray background presentation. It is included in the SharePoint style sheets provided in an OOTB install, so developers are free to implement a similar presentation in their own custom implementations.

Customizing the HTML Editor Field Control

The rich HTML Editor field control may be the most commonly used control on page layouts within Publishing sites. The control provides content authors with the capability to author rich content using formatting, tables, hyperlinks, and images, as well as modify the font color and size—all with a slick live preview of the rendered content. This control, shown in Figure 14-4, is very similar to the familiar formatting toolbars available in common word processing applications such as Office Word 2007.

Figure 14-4

Figure 14-4

While the flexibility provided by the HTML Editor field control can be very useful in many cases, at other times it is necessary to restrict what content authors can and cannot do. For instance, it may not be desirable to allow content authors to pick the color or font size of the text, but should instead be defined using specific CSS classes. At other times, content authors might want to disallow the use of images or tables within a content field. To satisfy these needs, the HTML Editor field control provides a way to enable and disable buttons, as well as create custom buttons and specify the CSS classes available for use within a site.

Enabling and Disabling Buttons

Enabling and disabling buttons on the HTML Editor field control is very easy. There are two was to control the buttons. One way is to open the page layout containing the control in SharePoint Designer in Design view and select the field control. The Tag Properties tool window shows all available settings on the control. Changing one of the values adds an attribute to the field control in the source of the page layout. The other way to control the Enabled state of a button is to manually add the Boolean attribute to the field control markup directly in the page. The code in Listing 14-3 shows the markup for a field control that has disabled the capability to add images and tables, as well as provide a way for the content author to view the raw HTML markup.

Listing 14-3: Customizing the HTML Editor field control

<PublishingWebControls:RichHtmlField id="Content" FieldName="PublishingPageContent"  AllowImages="False" AllowTables="False" AllowTextMarkup="True" AllowHtmlSourceEditing="False" />

The following table describes the available Boolean attributes:

Control Attribute

Description

AllowExternalUrls

Specifies whether the content can contain references to targets within the current site or external to the site

AllowFonts

Specifies whether the content can contain <font> tags

AllowHeadings

Specifies whether the content can contain HTML headings (<h1>, <h2>, <h3>, <h4>, <h5>, <h6>)

AllowHtmlSourceEditing

Specifies whether the content owner can view the raw HTML markup of the content and edit it

AllowHyperlinks

Specifies whether the content can contain links (<a>)

AllowImages

Specifies whether the content can contain images

AllowLists

Specifies whether the content can contain HTML lists (<ol> or <ul>)

AllowReusableContent

Specifies whether the content owner can add reusable content or not

AllowTextMarkup

Specifies whether the content can contain formatting markup (<b>, <em>, <u>)

DisableCustomStyles

Specifies whether the content author can select from predefined CSS styles

DisableBasicFormattingButtons

Specifies whether the content author can use the text formatting buttons for bold, italic, and underlined text, as well as indentation

Adding Custom Buttons

Another bit of customization that can be implemented on the HTML Editor field control is the capability to create custom buttons in the floating toolbar. While not a trivial task, creating custom buttons can provide an even more specialized authoring experience. Creating a button involves writing JavaScript and registering it with the HTML Editor using XML.

Consider the following example of using a MOSS 2007 Publishing site that contains significant editorial content. The developers want to enable the content owners, the editors, to use a type of microformat called XHTML Friends Network (XFN). The XFN microformat provides a way to represent human relationships using HTML links.

What Are Microformats?

According to Wikipedia, "a microformat is a Web-based data formatting approach that seeks to reuse existing content as metadata, using only XHTML and HTML classes and attributes." In other words, today XHTML and HTML are used to define how content should be rendered (such as the <b>, <em>, or <u> tags) or what it should do (such as <a>). The goal of microformats is to add more structure to the data to define what the data is. For instance, there are proposed microformats for physical addresses, calendar items, and species (living things), to name a few.

For more information on microformats and the XHTML Friends Network (XFN), refer to the following pages on Wikipedia: www.andrewconnell.com/go/251 and www.andrewconnell.com/go/252.

XFN links are not very complicated. The main difference is that an XFN link contains an extra attribute rel, which contains a space-delimited list of specific identifiers such as me, friend, met, and colleague. Rather than tell content owners how to create these special links, the developers wanted to provide an easy and self-explanatory way for the editors to create them on their own. When the user has selected some text in the field control, a button should be enabled, allowing the content owner to enter a URL and rel values for the link, as shown in Figure 14-5 (notice the XFN button on the last row of the toolbar, just below the Select button).

Figure 14-5

Figure 14-5

Clicking the XFN button will generate two JavaScript pop-up dialogs: one prompting for the URL and one prompting for the rel values. After the values for both pop-up dialogs have been entered, the button generates the HTML link. The result is shown in Figure 14-5. The extra image is rendered using a CSS trick:

a.xfnRelationship[rel~="me"]
{
padding-right: 21px;
background: url(/_layouts/xfn/xfn-me.png) no-repeat right;
}

To create this button, first create a new JavaScript file RTExfnMicroformat.js in the [..]\12\TEMPLATE\LAYOUTS\1033 folder. This file contains the function that will create the button, as well as two additional functions. First, use the **RTE2_RegisterToolbarButton()**function to create the toolbar item as shown in Listing 14-4. This function has sevenx input parameters:

  • ID—ID of the button

  • IconURL—Location of the image used in the button

  • Text—Text to appear on the toolbar for the button

  • ToolTip— Text to appear when a user hovers the mouse over the button

  • ClickCallback—Name of the JavaScript function to be called when the button is clicked. This function does all the work.

  • ResetStateCallback—Name of the JavaScript function to be called when the state of the editor changes. This method would be called when the user enters, selects, or deselects text in the editor. This is used to change the enabled state of the button.

  • Arguments—Array of arguments to pass to each of the callback functions when they are executed

Listing 14-4: RTE2_RegisterToolbarButton() JavaScript function called to create custom button in the HTML Editor field control

RTE2_RegisterToolbarButton("xfnMicroformat", 
                            "_layouts/xfn/xfn-small.png", 
                            "XFN", 
                            "Add XHTML Friends Network microformat link", 
                            XfnButtonOnClick,
                            XfnButtonOnResetState,
                            new Array());

Next, create the two callback functions, as shown in Listing 14-5. The first one, XfnButtonOnClick(), does all the work when the button is clicked. The second, XfnButtonOnResetState(), is used to enable or disable the button. In this example, the button should only be enabled when text has been selected:

Listing 14-5: HTML Editor field control custom button callback functions

// The method that is called when the button is clicked.
function XfnButtonOnClick(strBaseElementID, arguments) {
  // get reference to document currently being edited
  var docEditor = RTE_GetEditorDocument(strBaseElementID);
  if (docEditor == null) { return; }
  // get reference to the selected text
  var selectedRange = docEditor.selection.createRange();

  // prompt user for url and microformat
  var url = prompt("Enter the person's URL:","http://www.someone.com");
  var xfn = prompt("Enter the XHTML friend (XFN) relationships:\nPossible values: me, parent, child, colleague, friend, spouse, sweetheart, met", "");

  // create the <a> HTML for the blog link
  selectedRange.pasteHTML("<a href=\"" +url +"\" class=\"xfnRelationship\" rel=\"" +xfn +"\">" +selectedRange.htmlText + "</a>");

  // restore selection
  RTE_RestoreSelection(strBaseElementID);

  return true;
}

// The method that is called when the button's state is reset.
function XfnButtonOnResetState(strBaseElementID, arguments) {
  // get reference to document currently being edited
  var docEditor = RTE_GetEditorDocument(strBaseElementID);
  if (docEditor == null) { return; }
  
  // restore selection
  RTE_RestoreSelection(strBaseElementID);

  // if text is selected, show the button
  if (docEditor.selection.createRange().text.length != 0){
    RTE_TB_SetEnabledFromCondition(strBaseElementID, true, "xfnMicroformat");
  } else {
    RTE_TB_SetEnabledFromCondition(strBaseElementID, false, "xfnMicroformat");
  }
  return true;
}

Notice that a handful of predefined JavaScript functions are being called throughout the callbacks. Unfortunately, these functions are not documented, but developers can pick through the files that define them when creating custom buttons. The main JavaScript files involved in the HTML Editor field control are HtmlEditor.js, FORM.js, and AssetPickers.js, which are all found in the [..]\12\TEMPLATE\LAYOUTS\1033 folder.

With the JavaScript created, the next thing to do is make the HTML Editor field control aware of the custom button. When a page loads in Edit mode, the field control looks in a specific XML file within the master page gallery for all additional JavaScript files that should be loaded. The file, http://[..]/catalogs/masterpage/Editing menu/RTE2ToolbarExtension.xml, contains a list of all the custom buttons to load onto the field control's toolbar. Each XML node in this file should point to the JavaScript file that contains the button registration function, as well as the callbacks. To register the XFN button, add the following to this file and then go through the save, check-in, publish, and approval process:

<?xml version="1.0" encoding="utf-8" ?>
<RTE2ToolbarExtensions>
  <RTE2ToolbarExtraButton id="XfnMicroformat" src="RTEXfnMicroformat.js"/>
</RTE2ToolbarExtensions>

After loading the JavaScript file, the HTML Editor field control will then call the **RTE2_RegisterToolbarButton()**function to register and create the button.

Depending on the custom button solution, extra steps may be needed, such as in the case of the XFN button, which needed extra CSS classes to display and deploy images. The code download available for this book contains the complete solution packaged up in a WSS solution package, including a Feature that provisions the CSS file to the Style Library. Another process for deploying the custom button via a Feature is discussed in detail in the section "Deploying Page Editing Toolbar Customizations" later in the chapter, as the process of registering HTML Editor field control buttons and page editing toolbar customizations are similar. The only manual step in the provided solution is to make the necessary changes to the RTE2ToolbarExtension.xml file to make the HTML Editor field control aware of the custom button.

Customizing Available CSS Classes

The previous section, "Enabling and Disabling Buttons," demonstrated how Publishing site developers and designers can enable or disable certain buttons on the HTML Editor field control toolbar to keep content owners from using certain formatting options. The downside to this approach is that it limits content formatting options when some content needs to be styled. The preferred way for designers to implement and maintain a consistent look and feel in a site is to use CSS classes. These style sheets contain the branding and layout information for the entire site. The best part about them is that they are typically global to an entire site, so branding changes only have to be made in one spot, enabling designers and developers to centrally manage the site's look and feel. This eliminates the need for inline styles or formatting that is defined on a case-by-case basis, such as the following:

<span style="font-weight:bold; color:red;">Company Name</span>

Instead, designers can use a specific CSS class. This specific class makes maintaining a common look and feel easy because the styling is defined in a single place.

The HTML Editor field control provides an another formatting capability in addition to turning on/off certain buttons (such as text formatting for bold, italic, underlined, or colored text). The HTML Editor field control will detect all CSS classes defined on the page that match a specific naming pattern and display them in the Styles selector in the toolbar of the field control. Any style with the class name containing the prefix of ms-rteCustom- is added to the list of possible CSS classes to choose from. The field control is intelligent enough to only display the classes that are available based on the context of the editor.

For example, add the following CSS class either to an existing CSS file loaded on the page or directly to the page layout (again, it does not matter how it gets on the page, only that it is defined in the page somewhere):

Figure 14-6

Figure 14-6

The HTML Editor field control also provides the capability to use specific CSS styles for a particular HTML Editor field control. The field control contains a PrefixStyleSheet property that can change the CSS class prefix for a particular field control instance from the default ms-rte-Custom- prefix.

Telerik RadEditor Lite for MOSS

The previous section covered the different customization options available to developers when using the HTML Editor field control. One of the most significant pain points associated with this control is that it is only supported for use within Internet Explorer. Other browsers, including the Mozilla-based browsers such as Firefox and Apple's Safari, are not supported and can't offer a full hassle-free experience. To address this issue, Microsoft has worked out an arrangement with Telerik (www.andrewconnell.com/go/253) to provide an HTML Editor field control feature equivalent, yet cross-browser, experience.

The Telerik RadEditor Lite for MOSS is available as a free downloadable add-on to anyone who has a valid MOSS 2007 license (it is not available for WSS 3.0–only installations). The RadEditor Lite for MOSS is a slimmed-down version of the more robust and commercial RadEditor for MOSS product. Like the HTML Editor field control, the RadEditor Lite can be customized in many of the same ways.

It is recommended that developers use the Telerik RadEditor Lite for MOSS in lieu of the Microsoft-provided HTML Editor field control. The RadEditor Lite for MOSS enables developers to provide a pure cross-browser authoring experience while leveraging the same customization techniques that the MOSS HTML Editor field control offers, such as custom CSS styles and custom buttons.

Go to the SharePoint 2007 section of the Telerik Web site (www.andrewconnell.com/254) to download and get more information about the RadEditor Lite product, as well as documentation on installation, customization tasks, and community support options.

Customizing the Page Editing Toolbar

All Publishing sites utilize the Page Editing Toolbar (PET). The PET provides content authors and owners with all the functionality needed to manage a page—from creating and editing pages to managing workflow, page settings, and more. The PET is divided into three sections:

  • Page Status Bar—This is the top portion of the PET. It provides informational messages about the page, such as version, state, status, and when is it scheduled to start publication.

  • Page Editing Menu—This is the lower-left portion of the PET. It includes menus of all the different actions that can be undertaken on the current page. If an action is not available (such as checking a page out because it is already checked out), then it is disabled.

  • Quick Access Buttons—This is the lower-right portion of the PET. It includes buttons similar to the actions found in the Page Editing Menu section, but only actions that are available in the current context are shown.

The PET is very functional and essentially complete OOTB, with all the necessary tasks needed to create and manage a piece of content in a Publishing site, but it does provide a way for developers to create custom menus, menu items, and buttons. The process involves creating a class that will do the work and then modifying an XML file to make the PET aware of the new menus, items, and buttons. Luckily, the code for both new menu items and buttons is identical. The following sections demonstrate how to create custom editing menu items and custom buttons

A common request from customers and designers is knowing which page layout ASPX file corresponds with a particular content page. While the ASPX can be determined by first checking the name of the page layout from the Page Settings page (PET: Page@@>Page Settings and Schedule) and using that title to find the corresponding page layout ASPX file in the master page gallery, an easier way can be provided. The solution is to create a new application page that provides additional publishing details about the current page, as shown in Figure 14-7.

Figure 14-7

Figure 14-7

To get to this page, content owners want to simply click a button in the PET Quick Access Button area or select an item from the PET Page Editing Menu, as shown in Figure 14-8.

Figure 14-8

Figure 14-8

The following sections create one of each to demonstrate both processes. These menu items and buttons center on the concept of PET actions, or console actions. The first step is to create a console action, as it can be used as either a menu item or a button.

Creating Page Editing Toolbar Actions

As previously stated, menu items and buttons in the PET are founded on the idea of actions—specifically, console actions. Creating a console action involves creating a new class that inherits from the Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions.ConsoleAction class and overriding a handful of properties. Many of the properties can be set from the XML used to register the action in the PET Page Editing Menu or the PET Quick Access Buttons areas. However, developers can restrict the console action so that it doesn't accept values other than those defined within the console action by simply overriding the get portion of the property and ignoring the set portion. This way, the values specified in the XML are never applied.

To create a console action, create a new C# Class Library project in Visual Studio and add a reference to the Microsoft.SharePoint and Microsoft.SharePoint.Publishing assemblies. Next, create a new class, PublishingPageDetailAction, that inherits from Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions.ConsoleAction. Set the default name of the action within the class constructor, as shown in Listing 14-6.

Listing 14-6: Page Editing Menu ConsoleAction class

using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Publishing.WebControls;
using Microsoft.SharePoint.Publishing.WebControls.EditingMenuActions;

namespace WROX.ProMossWcm.Chapter14 {
  public class PublishingPageDetailAction : ConsoleAction {
    public PublishingPageDetailMenuItem ()
      : base() {
      this.DisplayText = "Page Details";
    }
  }
}

The next thing to set is when the action is visible. This is done by overriding the ConsoleAction.RequiredStates property. This property returns either a single value from the enumeration Microsoft.SharePoint.Publishing.WebControls.AuthoringStates or a bitmask of multiple values. In this case, the Page Detail menu item and button should always be visible when the PET is active, so the AuthoringStates.EditingMenuEnabled is used. Add the property shown in Listing 14-7 to the PublishingPageDetailAction class.

Listing 14-7: ConsoleAction.RequiredStates property

public override AuthoringStates RequiredStates {
  get { return AuthoringStates.EditingMenuEnabled; }
}

Now the action needs to be configured to specify who can and cannot see the item or button. This is done by overriding the ConsoleAction.UserRights property. Similar to the RequiredStates property, UserRights returns a bitmask of the Microsoft.SharePoint.SPBasePermissions enumeration. In this case, everyone who has access to the PET should be able to see this action, so the SPBasePermission.EmptyMask is used, as shown in Listing 14-8.

Listing 14-8: ConsoleAction.UserRights property

public override SPBasePermissions UserRights {
  get { return SPBasePermissions.EmptyMask; }
}

All menu items and buttons can have an associated image (refer to Figure 14-8). In this case, the PublishingPageDetailAction will have a default image set but it will also allow for the image to be overwritten in the XML, as shown in Listing 14-9.

Listing 14-9: ConsoleAction.ImageUrl

private string _imageUrl;
public override string ImageUrl {
  get {
    if (string.IsNullOrEmpty(_imageUrl))
      return "~/_layouts/images/info16by16.gif";
    else return _imageUrl;
  }
  set { _imageUrl = value; }
}

Finally, the action must do something when it is clicked by the user! This can be accomplished on either the client side or the server side. To handle the click from the server side, override the ConsoleAction.RaisePostBackevent() method. If any errors are encountered in the postback, instead of throwing an exception, developers should call the ConsoleAction.ShowError() method, passing in the exception as well as a Microsoft.SharePoint.Publishing.WebControls.ConsoleError object. The server-side approach is helpful when performing some operation on the page, such as saving or checking-in, or some other server-side task.

In the case of the PublishingPageDetailAction console action, the user should be taken to a specific page. This does not require a postback; client-side script can be used. To do this, override the ConsoleAction.href property. When the menu item or button is clicked, the user should be taken to the Page Detail application page. This page needs to know what page it should show the details for, so the URL needs to contain some information such as the SharePoint site where the page resides and the ID of the page in the Pages list. Add the code in Listing 14-10 to the PublishingPageDetailAction class.

Listing 14-10: ConsoleAction.href override

public override string href {
  get {
    string pageDetailUrl = "_layouts/WROX/PublishingPageDetail.aspx";
    return String.Format("javascript:window.location='{0}/{1}?pageid={2}';",
                         pageDetailUrl,
                         SPContext.Current.Web.Url.ToString(),
                         SPContext.Current.ListItem.ID.ToString());
  } 
}

At this point the console action is complete. The last two steps are to register a new menu item or button on the PET and perform the necessary deployment steps.

Adding Items to the PET Page Editing Menu

With the console action created, it now needs to be added to the PET. As shown in Figure 14-8, it is added as a menu item in a new menu called Utilities. The Page Editing Menu structure is defined by the XML file EditingMenu.xml located in [..]\12\TEMPLATE\LAYOUTS\EditingMenu. This is not the file developers should modify, however, to add custom menu items. Rather, this file contains a reference near the top where custom menu items are defined:

<?xml version="1.0" encoding="utf-8" ?> 
<Console>
   <customfile FileName="CustomEditingMenu" />
   <references>
   <!-- omitted from the book for readability -->

This <customfile /> node tells the PET to look for the file CustomEditingMenu.xml in a special location of the site hierarchy: http://[..]/_catalogs/masterpage/Editing Menu. This file is a customized instance in the site collection so it needs to be edited directly in SharePoint Designer. Another way to modify the file is covered in the section "Deploying Page Editing Toolbar Customizations." This file contains two main areas: references and structure. The <references> section is similar to the <% @Register %> directive in *.ASPX and *.ASCX files. This where a reference is established to the console action class in the assembly previously created. The second section, <structure>, is where the new menu and menu item is created. Replace the markup in the CustomEditingMenu.xml with the markup in Listing 14-11.

Listing 14-11: CustomEditingMenu.xml

<?xml version="1.0" encoding="utf-8" ?>
<Console>
  <references>
    <reference TagPrefix="wrox"
               assembly="Chapter14PageEditingToolbar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c591e70cfdf9ce4f"
               namespace="WROX.ProMossWcm.Chapter14" />
  </references>
  <structure>
    <ConsoleNode Sequence="500" ConfigMenu="Add" href="javascript:"
                 AccessKey="L" 
                 DisplayText="Utilities"
                 ImageUrl="/_layouts/images/saveitem.gif"
                 UseResourceFile="false"
                 UserRights="EmptyMask" 
                 ID="saPageLinks">
      <ConsoleNode DisplayText="Page Details"
                   ImageUrl="/_layouts/images/info16by16.gif"
                   UseResourceFile="false"
                   Action="wrox:PublishingPageDetailMenuItem"
                   ID="wroxPublishingPageDetailMenuItem">
      </ConsoleNode>
    </ConsoleNode>
  </structure>
</Console>

Notice in Listing 14-11 how the two <ConsoleNode /> elements are nested. This is what creates the new menu with a menu item. The only other thing to note in this code listing is the Action attribute on the inner <ConsoleNode />. This attribute is used just like an ASP.NET 2.0 server control in an *.ASPX or *.ASCX file, as it contains the tag prefix defined in the <references /> section above, and the name of the class of the console action.

Save all changes, and check in, publish, and approve the CustomEditingMenu.xml file. Because this file resides in the master page gallery, it conforms to the same approval and workflow settings as master pages, page layouts, and preview images. The new menu and menu item should now appear in the PET.

Adding Buttons to the PET Quick Access Buttons

Adding a new button to the PET Quick Access Button area is almost identical to creating a new menu item in the Page Editing Menu area. Similar to the Page Editing Menu, the PET uses the file QuickAccess.xml located in the [..]\12\TEMPLATE\LAYOUTS\EditingMenu folder to build the buttons. This file points to the CustomQuickAccess.xml file in the master page gallery for all custom buttons. The structure of this XML file, shown in Listing 14-12, is similar to that of the CustomEditingMenu.xml file except that there are no submenu options.

Listing 14-12: CustomQuickAccess.xml

<?xml version="1.0" encoding="utf-8" ?>
<Console>
  <references>
    <reference TagPrefix="wrox"
               assembly="Chapter14PageEditingToolbar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=c591e70cfdf9ce4f"
               namespace="WROX.ProMossWcm.Chapter14" />
  </references>
  <structure>
    <ConsoleNode Sequence="1"
                 ConfigMenu="Add"
                 HideStates="PageHasCustomizableZonesFalse|PageHasFieldControlsFalse"
                 Action="wrox:PublishingPageDetailAction"
                 ID="wroxPublishingPageDetailQuickAccessButton" />
  </structure>
</Console>

Notice an additional attribute in the <ConsoleNode /> element: HideStates. This is a bitmask of the AuthoringStates enumeration, defining when the button should or should not be shown.

Just like the Page Editing Menu, this file conforms to all approval and workflow settings for the master page gallery, so it should be checked in, published, and approved for the changes to be seen by everyone. Otherwise, only the person making the changes to the XML will see the changes.

Deploying Page Editing Toolbar Customizations

Last step: deployment. The deployment of custom PET menu items and buttons is quite simple. The two XML files do not need to be deployed because the changes have already been applied to the site collection. However, the console action needs to be deployed. The assembly containing the console action can be deployed to the server's GAC or the targeted Web application's \BIN folder. The console action also needs to be flagged as a <SafeControl /> in the web.config file regardless of where the assembly is deployed. All of this can be done with a WSS solution package.

One thing just doesn't feel right though: The two XML files defining the custom menu item and button were modified using SharePoint Designer. Does that mean in order to deploy the changes in multiple environments a developer or site owner needs to make this change on all environments manually? If the process followed in this chapter is what is used to implement the changes, then the answer is yes. However, this is not the only way!

Staying true to the theme of this book, whereby both SharePoint customization and development techniques are demonstrated, consider the following approach. The only part of the previously demonstrated process that requires manual intervention is the modification of the two XML files in the master page gallery. Does that mean these files can be replaced with uncustomized instances that point to the file system, just as master pages and page layouts can? Unfortunately, no—these files need to exist as customized instances in the master page gallery. This means that provisioning the files using WSS 3.0 Features is not possible, but deployment can still occur using Features with no manual work.

Instead of using the file provisioning technique, use Feature receivers to do the work of modifying the XML files. The associated code for this chapter demonstrates this approach. The process is as follows: A Feature is used to trigger the deletion of the existing XML files, replacing them with new, customized instances that contain the necessary XML to register the custom menu item and button in the PET. Sure, the files could be programmatically opened and modified using code, but that just adds complexity. Instead, the approach of deleting the old files and creating new files keeps the process simple. The trick is to delete the old XML files before creating the new ones. One Feature, Chapter14DeleteCustomizedPetFiles, deletes the two XML files when activated (see Listing 14-13).

Listing 14-13: Chapter14DeleteCustomizedPetFiles Feature receiver deleting files

using System;
using System.IO;
using Microsoft.SharePoint;

namespace WROX.ProMossWcm.Chapter14 {
  public class Chapter14DeleteCustomizedPetFilesReceiver : SPFeatureReceiver {
    public override void FeatureInstalled (SPFeatureReceiverProperties props){}
    public override void FeatureUninstalling (SPFeatureReceiverProperties props){}

    public override void FeatureActivated (SPFeatureReceiverProperties props) {
      using (SPSite siteCollection = props.Feature.Parent as SPSite) {
        using (SPWeb site = siteCollection.RootWeb) {
          // delete the two customization files
          DeletePetCustomizationFiles(site, "CustomEditingMenu.xml");
          DeletePetCustomizationFiles(site, "CustomQuickAccess.xml");
        }
      }
    }

    private void DeletePetCustomizationFiles (SPWeb site, string fileName) {
      // delete the CustomEditingMenu.xml
      SPFile petCustomizationFile = site.GetFile("_catalogs/masterpage/Editing Menu/" + fileName);
      petCustomizationFile.Delete();
    }
  }
}

Another Feature, Chapter14CreatePetCustomizationFiles, creates two new instances of the files programmatically upon activation (see Listing 14-14).

Listing 14-14: Chapter14CreatePetCustomizationFiles Feature receiver creating files

using System;
using System.IO;
using Microsoft.SharePoint;

namespace WROX.ProMossWcm.Chapter14 {
  public class Chapter14CreatePetCustomizationFilesReceiver : SPFeatureReceiver {

    private const string CUSTOM_EDITING_MENU = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Console>" + /* omitted from the book for readability */ + "</Console>";
    private const string CUSTOM_QUICK_ACCESS = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><Console>" + /* omitted from the book for readability */ + "</Console>";
                                                
    public override void FeatureInstalled (SPFeatureReceiverProperties props){}
    public override void FeatureUninstalling (SPFeatureReceiverProperties props){}
    public override void FeatureDeactivating (SPFeatureReceiverProperties props){}

    public override void FeatureActivated (SPFeatureReceiverProperties props) {
      using (SPSite siteCollection = props.Feature.Parent as SPSite) {
        using (SPWeb site = siteCollection.RootWeb) {
          CreatePetCustomziationFile(site, 
                                     "CustomEditingMenu.xml", 
                                     CUSTOM_EDITING_MENU);
          CreatePetCustomziationFile(site, 
                                     "CustomQuickAccess.xml", 
                                     CUSTOM_QUICK_ACCESS);
        }
      }
    }

    private void CreatePetCustomziationFile (SPWeb site, 
                                             string fileName, 
                                             string content) {
      using (MemoryStream mStream = new MemoryStream()) {
        using (StreamWriter sWriter = new StreamWriter(mStream)) {
          sWriter.WriteLine(content);
          sWriter.Flush();

          // get reference to folder and create file
          SPFolder editingMenuFolder = site.GetFolder("_catalogs/masterpage/Editing Menu");
          SPFile petCustomizationFile = editingMenuFolder.Files.Add(fileName, 
                                                                    mStream);

          // check in & publish
          if (petCustomizationFile.Item.Level == SPFileLevel.Checkout)
            petCustomizationFile.CheckIn("");
          petCustomizationFile.Publish("");
          petCustomizationFile.Approve("");

          sWriter.Close();
          mStream.Close();
        }
      }
    }

  }
}

Both of these Features, Chapter14DeleteCustomizedPetFiles and Chapter14CreatePetCustomizationFiles, are hidden Features. They are activated by another visible Feature, Chapter14PageEditingToolbar, that activates each in the proper order, as shown in Listing 14-15.

Listing 14-15: Chapter14PageEditingToolbar Feature definition

<?xml version="1.0" encoding="utf-8" ?>
<Feature xmlns="https://schemas.microsoft.com/sharepoint/" 
         Id="5116F0D5-8B50-4F42-A676-C44DFC9C6B93"
         Title="Chapter 14 - Page Editing Toolbar Customizations"
         Scope="Site" 
         Hidden="FALSE"
         Version="1.0.0.0">
  
  <ActivationDependencies>
    <!-- Chapter14DeleteCustomizedPetFiles -->
    <ActivationDependency FeatureId="A168B00F-3E44-49A5-9911-959A29141910" />

    <!-- Chapter14CreatePetCustomizationFiles -->
    <ActivationDependency FeatureId="5BC41C2E-8BA7-4E96-B150-C8FC14734747" />
  </ActivationDependencies>
  
</Feature>

Activation of the Chapter14PageEditingToolbar Feature triggers the process of deleting the existing XML files and creating the new XML files that define the PET customizations. Figure 14-9 contains the process flow for the Feature activation.

Figure 14-9

Figure 14-9

In addition, the Features contain logic to "undo" everything upon deactivation, as shown in Figure 14-10.

Figure 14-10

Figure 14-10

This is another example demonstrating that developers are not restricted to using the SharePoint customization approach to deployment. Rather, they can create a much more repeatable and automated deployment process using SharePoint development techniques.

Note

Note that the deployment process demonstrated in this section also applies to the same customizations that need to be made in the HTML Editor field control XML files covered in the section "Adding Custom Buttons."

Summary

MOSS 2007 ships with various capabilities developers can use to create very customized Publishing sites. These, as well as master pages, page layouts, custom field controls, and custom Web Parts, enable developers to craft a unique site on the MOSS 2007 platform using the Publishing Features. In addition to the many customization options, Microsoft has made WSS 3.0 and MOSS 2007 (as well as Publishing-specific aspects) extensible, enabling developers to extend and modify the OOTB experience for content authors.

This chapter discussed and demonstrated the various ways a Publishing site can be customized and extended. The most common field control, the HTML Editor field control, provides many options for customization, such as specifying selectable CSS classes, enabling and disabling the formatting buttons, as well as creating custom buttons. While the HTML Editor field control provides many opportunities for customization, it falls short in the area of cross-browser support. This chapter also touched on the recommended alternative to the HTML Editor field control: Telerik's RadEditor Lite for MOSS.

Finally, the subject of creating custom menu items and buttons for the Page Editing Toolbar was covered. Customizing the PET can provide a very specialized experience for content owners; thus, it is a very powerful technique in the Publishing site developer's toolbox.

Additional Resources