Friday 26 April 2013

How to make the 'Description' field mandatory for SharePoint 2010 site creation - Part 2

Part 1 of this post can be found here 

In part 1 I demonstrated how I created a new version of newsbweb.aspx and added validation to this page to ensure that sites created with this form had the description field completed. However, the next part of this problem is to ensure that this form is used for every new site created. 

The first thing I had to do was determine how many different ways there are to create a site using the UI. From my count, there are no less than four. They are listed below:

  1. Site Actions, New Site (This opens the silverlight dialog box)
  2. Site Actions, More Options (Same as above)
  3. A SharePoint application page called create.aspx (this is the html alternative to the silverlight control, and it references newsbweb.aspx)
  4. Site Actions, View All Site Content (a button on this page opens the Silverlight dialog)
  5. Site Settings, Sites and Workspaces (a button on this page opens newsbweb.aspx)
The first three are all in the same place, the Site Actions menu, which can be modified directly on your master page. You can do this through a feature using customactions (hide the old one and create a new one) as well, but I chose to modify the master page directly as it is simpler. I will go through closing off each site creation one by one.

1. 

To modify the Site Actions menu on the master page, look for the section that defines the Site Actions <SharePoint:SiteActions> and within that you will find an entry for each site action tagged by <SharePoint:MenuItemTemplate>. If you look at the MenuItemTemplate with ID MenuItem_CreateSite, you will see that there is an attribute called ClientOnClickScriptContainingPrefixedUrl. I don't know who named that attribute but they deserve an award. remove this attribute and replace it with ClientOnClickNavigateUrl="~site/_layouts/newsbweb2.aspx" to point it to your new page.

2. and 3. 

Find the MenuItemTemplate with ID MenuItem_Create and remove the attribute mentioned above and replace it with ClientOnClickNavigateUrl="~site/_layouts/create2.aspx"  You now need to create a copy of create.aspx (sigh) which will eventually go in your layouts folder. All you need to do in this copied version is replace any reference of newsbweb.aspx to newsbweb2.aspx of which there are a few.


4.

Find the MenuItemTemplate with ID MenuItem_ViewAllSiteContents and change the value of the ClientOnClickNavigateUrl to "~site/_layouts/viewlsts2.aspx". Yes, again you will need to copy your viewlsts.aspx page and create a new version. In this version you will need to hide the "Create" button using css.


<style>
#ctl00_PlaceHolderMain_ToolBar_RptControls_diidIONewList {display:none;}
</style>

You then need to find the <SharePoint:SPLinkButton> with ID diidIONewList and insert a new SPLinkButton after it to recreate the same effect.

<SharePoint:SPLinkButton ID="SPLinkButton1" runat="server" NavigateUrl="~site/_layouts/create2.aspx" text="Create" ImageUrl="/_layouts/images/createcontent.gif" ShowImageAndText="true" HoverCellActiveCssClass="ms-buttonactivehover" HoverCellInActiveCssClass="ms-buttoninactivehover" />

Notice the new button points to create2.aspx and this button looks and behaves exactly the same as the old one, so nobody is the wiser.

5.

I saved the best for last... As you probably predicted, you will need to create a copied version of the Sites and Workspaces application page mngsubwebs.aspx and modify it to point to your new page. You can do this by finding the create button and changing the NavigateUrl value, shown below.

<wssuc:ToolBarButton runat="server" id="newsite"
ImageUrl="/_layouts/images/newitem.gif"
ToolTip="<%$Resources:wss,multipages_createbutton_text%>"
Text="<%$Resources:wss,multipages_createbutton_text%>"
NavigateUrl="cw-newsbweb.aspx"
accesskey="N"/>

Now, this page is accessed through site settings, and you can create a new version of site settings page (settings.aspx) and update your master page if you want to, but the client site already uses a feature that hides certain options from the site settings page and recreates them if the user is an administrator. So all I did was repeat this for the Sites and Workspaces setting and when recreating it, made sure that it pointed to the mngsubwebs2.aspx page. Information can be found all over the web about how to use customactions to hide items from this page so I won't document that here.

So, that's me done and as far as I can see, there are now no ways to create sites on this site collection without entering a description. I know, it was a tedious and cumbersome, and messy process... but the client preferred this solution and I agree with them. There is no point in the event receiver solution as it will simply annoy users.

Finally, as I said in Part 1, you would be better to not add these new application pages to your 14 hive manually. Instead, create a new VS2010 project, map a folder to your layouts folder, and add these application pages here. That way when you deploy the solution the files will be added on all front end server automatically and removed when you retract the solution.

I hope this has been helpful/informative for someone. Please leave comments or let me know if you have a better way!

Tal

Thursday 25 April 2013

How to make the 'Description' field mandatory for SharePoint 2010 site creation - Part 1

Hi all,

This is my first blog post, and I hope I can help someone out with it! If anyone reads this please comment to let me know your thoughts or any suggestions for improvement.

The Business Problem


I have been developing a solution for a client that involves site creation through a form. I am personally not a fan of this approach but the client had their justifications for this and insisted on this approach. Because the site is create by filling in a list form, the description field could be made mandatory so that all sites had a description. However, I noted that if someone creates a subsite of this using the SharePoint UI then "description" will no longer be mandatory. It was very important for the client to have a description for each site because the sites were being displayed in search results and the description was very important for this.

SharePoint provides no way (that I know of, or could find in research) of making this mandatory so I set out looking at the various options. The first was to stop users creating subsites, so that all sites are created using the form, and that was very quickly scrapped as an option! The first obstacle in making the "description" field mandatory is that there are two ways to create a new site. First is the _layouts/newsbweb.aspx application page and the second is the Silverlight dialog that allows you to create libraries, sites, pages, etc. Neither of these can be modified (if you want to stay within support limitations) so we need to get around these somehow. After spending a bit of time researching the issue I came up with the following two solutions and presented them to my client:


  1. Create an event receiver that cancels any new site requests if the description field is null

    You can create an event receiver that fires when a new web is being provisioned. The event receiver can look to see if the description field is filled out and if it is not, it will cancel the request and direct the user to a custom error page explaining why the site creation was cancelled

    This option is the simplest and requires least development time, but is not ideal. This is because when the user creates the site they will not know that description is mandatory and therefore a poor user experience would be provided, even though the solution would be achieved.
  2. Direct all site creation through a custom application page that ensures description is mandatory

    The Silverlight dialog can not be modified and therefore needs to be removed from the user journey. If all sites are created using a single application page that we control then we can easily ensure that all sites have a description.

    This site requires a bit more development time and the downside to this is that you lose the nice Silverlight control that Microsoft has developed and some people like. Personally I do not see this as a big loss. An additional downside to this method is that there are a number of different ways to create a SharePoint site. We must find all these different pathways and ensure that each is taken into account. I will explain more below
The client chose method 2. The additional development time, and more complicated solution were preferred to a solution where the user journey was not clear. 

How I did it...


The first thing that I needed to do was create a custom application page that would create a new site and check that the Description field was not left empty. The non-silverlight method of creating a sub-site is an application page called newsbweb.aspx which can be found in the 14/TEMPLATE/layouts/ folder. I copied this page and called is newsbweb2.aspx and kept it in the layouts folder. 

*NOTE* deploying files to this folder is not recommended, especially if you have more than on Web Front End server. I took this method only for development purposes and later packaged the files using Visual Studio (more on that later)

Once I had my own copy of the page I knew the next step was to add Javascript validation to the Description field. The input field ID is ctl00_PlaceHolderMain_idTitleDescSection_ctl01_TxtCreateSubwebDescription and once I had that I placed the following javascript in the page <head> tag. 

<script type="text/javascript">
    function CheckDescriptionPopulated() 

    {
        if (document.getElementById('ctl00_PlaceHolderMain_idTitleDescSection_ctl01_TxtCreateSubwebDescription').value == "") {
            alert("'Description' field can't be empty.");
        }
     
    }
</script>


This Javascript, I knew, would validate the field but I was not sure how to call it. I am by no means an expert in ASP but it seemed to me that the ASP buttons could not be modified easily to allow me to call my javacript. I have included the markup for the button section below for reference.

<wssuc:ButtonSection TopButtons="true" BottomSpacing="5" ShowSectionLine="false" runat="server">
<Template_Buttons>
<asp:Button UseSubmitBehavior="false" runat="server" class="ms-ButtonHeightWidth" OnClick="BtnCreateSubweb_Click" Text="<%$Resources:wss,multipages_createbutton_text%>" id="BtnCreateSubwebTop" AccessKey="<%$Resources:wss,multipages_createbutton_accesskey%>"/>
</Template_Buttons>
</wssuc:ButtonSection>

I therefore decided to create my own buttons and hide the existing buttons (you cannot remove them as the page will throw an asp error). So I created my own buttons that looked exactly the same and called my Javascript using the new buttons. I put the new buttons in a <tr> because the whole page is basically one big table and I wanted my new page to look as close as possible to the old page. Markup below.


<tr>
<td>
</td>
<td>
<input type="button" class="ms-ButtonHeightWidth" value="Create" onclick="CheckDescriptionPopulated()" />
<input type="button" class="ms-ButtonHeightWidth" value="Cancel" onclick="goBack()" />
</td>
</tr>

Success! The new button validates the field... But it doesn't create a site... To make sure a site gets created, I looked at the "Create" button as it appears in the IE developer toolbar and noticed that the button calls a bit of javascript to create the site. So I added this to my function, so that it is only called AFTER the description has been validated. So my javascript now looks like this.

<script type="text/javascript">

    function CheckDescriptionPopulated() {

        if (document.getElementById('ctl00_PlaceHolderMain_idTitleDescSection_ctl01_TxtCreateSubwebDescription').value == "") {
            alert("'Description' field can't be empty.");
        }

        else {

            WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$PlaceHolderMain$ctl00$RptControls$BtnCreateSubwebTop", "", true, "", "", false, true))
        }
    }
</script>

Super Success! My form now validates the description field and if successful it creates the site! All I need to do now in order to finish the page off is hide the old buttons using css, and do a bit of styling on my new buttons to put them back in the same place as the old buttons and make sure they look the same as the old ones.
Now that I have a working application page, the next part is to make sure that everyone is forced to use it, and package the whole thing up nicely in a .wsp release. I will post again with the next part.

Tal