Cannot Store the WebPart Pages in the document libraries created from the custom document library definition in WSS 3.0. Now Bend It !!

Creating custom document library definition has been a common task in SharePoint 2007 development to implement the custom requirement with the definition. I came up with an interesting issue with the custom document library definition last week with one of my customer.

When we create web part pages in the WSS 3.0 SharePoint Site the document libraries created from the custom document library definitions are not available to store the Web part pages. The “spcf.aspx” application page is used to create the web part pages and the following code in the Inline coding restricts the document libraries of custom document library definition to be listed in the dropdown list of this page .

if ((spList.BaseType == SPBaseType.DocumentLibrary) &&

                        (spList.BaseTemplate == SPListTemplateType.DocumentLibrary || spList.BaseTemplate == SPListTemplateType.PictureLibrary)

 

The highlighted code only displays the document library of template type “101” and “109” which are the OOB template type of document library and the picture library respectively. The restriction is understandable that the other lists like Task, Announcements etc should not be listed in this page to store the web part pages. But the restriction based on the template type creates an issue with the custom document library definition whose template type will be unique and those libraries created from this custom definition will not be available in the “Spcf.aspx” page and you cannot store your web part pages in the document library created from the custom document library definition. It’s the same problem with when you are creating basic pages in the “bpcf.aspx” page.

If you remove the above mentioned highlighted code restriction in the “spcf.aspx” page then the document libraries created from the custom document library definition will be available to store the web part pages. Just making this change will resolve the issue but not in a supported way as we all know that making changes to the OOB files are not supported because they are owned by MICROSOFT…

It’s a by design behavior but needs a resolution and in the supported way is a quite tough ask !!

Following are the steps involved in customizing the “Spcf.aspx” in the supported way to fix this issue.

1. Copy the “Spcf.aspx” page and place it in the same layouts folder. Make the changes in the inline code and save it. Ok, Custom “Spcf.aspx” is ready but how to navigate to the custom spcf.aspx page for creating the web part pages. So the link for creating the web part page is available in the “Create.aspx” under the layouts, we need to change the navigate URL of this link in the create.aspx page to navigate to the custom spcf.aspx page. But making changes to the OOB page is not supported so we need to create a custom “Create.aspx” page with this change in the Navigation URL of the web part page creation link.

2. Copy the “Create.aspx” page and place it in the same layouts folder. Following is the code snippet which renders the link for the web part page creation which navigates to the “Spcf.aspx” page change the ‘href’ property to navigate to the custom “Spcf.aspx” page and save the custom “Create.aspx” page.

<td valign="top" width=100% class="ms-descriptiontext">

<a id="onetidWebPartPage" href="spcf.aspx" target="_self"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,viewlsts_wp_page_title%>" EncodeMethod='HtmlEncode'/></a>

     </td>

      Note: The same kind of change can be done for the “bpcf.aspx” and all the following customization will suit for it as well

3. Now we need to customize the SiteAction Menu to navigate to the Custom “Create.aspx” page. The “SiteAction” Menu is a SharePoint Web control rendered through the Master Page. So open the custom master page and find the following entry and change the NaviGateURL property of the “Create” Menu Item template.

<SharePoint:SiteActions runat="server" AccessKey="<%$Resources:wss,tb_SiteActions_AK%>" id="SiteActionsMenuMain"

                                    PrefixHtml="&lt;div&gt;&lt;div&gt;"

                                    SuffixHtml="&lt;/div&gt;&lt;/div&gt;"

                                    MenuNotVisibleHtml="&amp;nbsp;"

                                    >

                                    <CustomTemplate>

                                    <SharePoint:FeatureMenuTemplate runat="server"

                                          FeatureScope="Site"

                                          Location="Microsoft.SharePoint.StandardMenu"

                                          GroupId="SiteActions"

                                          UseShortId="true"

                                          >

                                          <SharePoint:MenuItemTemplate runat="server" id="MenuItem_Create"

                                                Text="<%$Resources:wss,viewlsts_pagetitle_create%>"

                                                Description="<%$Resources:wss,siteactions_createdescription%>"

                                                ImageUrl="/_layouts/images/Actionscreate.gif"

                                                MenuGroupId="100"

                                                Sequence="100"

                                                UseShortId="true"

                                                ClientOnClickNavigateUrl="~site/_layouts/Customcreate.aspx"

                                                PermissionsString="ManageLists, ManageSubwebs"

                                                PermissionMode="Any" />

                                          <SharePoint:MenuItemTemplate runat="server" id="MenuItem_EditPage"

                                                Text="<%$Resources:wss,siteactions_editpage%>"

                                                Description="<%$Resources:wss,siteactions_editpagedescription%>"

                                                ImageUrl="/_layouts/images/ActionsEditPage.gif"

                                                MenuGroupId="100"

                                                Sequence="200"

                                                ClientOnClickNavigateUrl="javascript:MSOLayout_ChangeLayoutMode(false);"

                                                />

                                          <SharePoint:MenuItemTemplate runat="server" id="MenuItem_Settings"

                                                Text="<%$Resources:wss,settings_pagetitle%>"

                                                Description="<%$Resources:wss,siteactions_sitesettingsdescription%>"

                                                ImageUrl="/_layouts/images/ActionsSettings.gif"

                                                MenuGroupId="100"

                                                Sequence="300"

                                                UseShortId="true"

                                                ClientOnClickNavigateUrl="~site/_layouts/settings.aspx"

                                                PermissionsString="EnumeratePermissions,ManageWeb,ManageSubwebs,AddAndCustomizePages,ApplyThemeAndBorder,ManageAlerts,ManageLists,ViewUsageData"

                                                PermissionMode="Any" />

                                    </SharePoint:FeatureMenuTemplate>

 

4. Now the custom master page will render you the site actions with the “Create” option which will navigate you to custom create page and from there you can navigate to the custom spcf.aspx page to create the web part pages.

5. So far so good… But the master page rendered from the site definition will apply it only to the Site Pages and the System pages not to the application pages (Layouts pages) because the application pages uses the application.master page. So when you are in any application pages then the Site Action will navigate you to OOB create.aspx page as we did not make changes to the application.master page. Again we cannot modify the application.master page directly… So start customizing the application.master page J

6. Copy the OOB application.master page from the Layouts folder and place it there with some custom name, say customapplication.master. When I started investigating to change the Site Action control rendering in the Application.master page I didn’t find it because the Site Action control is not rendered directly in the application.master page… The whole top navigation of the Application.Master page is rendered through the “topnavbar.ascx” user control from the control templates folder.

You can find the following snippet in the application.master page which renders the top navigation

<TD id="onetIdTopNavBarContainer" WIDTH=100% class="ms-bannerContainer">

            <asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server">

                  <wssuc:TopNavBar id="IdTopNavBar" runat="server" ShouldUseExtra="true"/> // choose wssuc is the TagPrefix included in the top of the application.master page

            </asp:ContentPlaceHolder>

       </TD>

7. So we need to customize the “TopNavBar.ascx” user control in the supported way again… Copy the “TopNav.ascx” and paste in under the Control Templates folder with some custom name, say “CustomTopNavbar.ascx”. Find the “SiteActions” web control in this user control and change the NaviGateURL property of the Create menu item template.

8. Now open the CustomApplication.master page and add the TagPrefix for the “CustomTopNavBar.ascx” control as follows

<%@ Register TagPrefix="Customwssuc" TagName="CustomTopNavBar" src="~/_controltemplates/CustomTopNavBar.ascx" %>

Render the customTopNavBar as follows

<TD id="onetIdTopNavBarContainer" WIDTH=100% class="ms-bannerContainer">

            <asp:ContentPlaceHolder id="PlaceHolderTopNavBar" runat="server">

                  <Customwssuc:CustomTopNavBar id="IdTopNavBar" runat="server" ShouldUseExtra="true"/>

            </asp:ContentPlaceHolder>

       </TD>

 

9. Save the “Customapplication.master”. Now how to switch the Layouts pages to use the Customapplication.master instead of the OOB application.master page.

10. There are properties available in the SPWeb type to switch the Master page of the Site pages and the system pages : They are “MasterURL” for system pages and the “CustomMasterURL” for site pages. But there is no property available to set the master page of application pages and it has been hard coded to use the application.master page in all the application pages.

11. To set the customapplication.master page to the application pages you can create a custom HTTPModule and can replace the master page of the application pages as follows.

public class MasterPageModuleHandler:IHttpModule

      {

        public void Init(HttpApplication context)

        {

            context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);

        }

        void context_PreRequestHandlerExecute(object sender, EventArgs e)

        {

            Page page = HttpContext.Current.CurrentHandler as Page;

            if (page != null)

            {

                page.PreInit += new EventHandler(page_PreInit);

            }

        }

        void page_PreInit(object sender, EventArgs e)

        {

            Page page = sender as Page;

            if (page != null)

            {

              

                // Is there a master page defined

                if (page.MasterPageFile != null)

                {

                    // only change the application.master files as those are the offenders

                    if (page.MasterPageFile.Contains("application.master"))

                    {

                        page.MasterPageFile = "/_Layouts/Customapplication.master";

                    }

                }

            }

        }

        public void Dispose()

        {

  }

}

12. Compile and place the DLL in the GAC and add the config entries for the custom HTTPModule.

13. If anyone find other way to switch the application.master page for the application then please let me know …

Oops !!! Done…. Now you can create web part pages and can store the pages in the custom document library.

The only thing which is left out is when you click on Create from the “View All site Contents” page ( Viewlsts.aspx) you will be navigated to the OOB create.aspx page… Hope you can find the supported customization for this with the given tips J