Archive for May, 2010

SP2010: Custom logout page

If you use a login mechanism that uses cookies to store your token, you may find the logout option a tad redundant.

What happens is, you choose to logout, get sent to the logout page where you are prompted to close the page, which you probably don’t want to do, then you click the link “go back to site” which on doing so, logs you back in! 

If your authentication provider (ADFS, IDM, etc) has a logout page, then you probably want to redirect them to that.  Or if you want to customize your own logout page, well more power to you!

To change where the  logout link brings you to, you need to modify the Welcome.ascx control template.

Browse to /14/TEMPLATE/CONTROLTEMPLATES and edit the welcome.ascx file.

You can add a property called ClientOnClickNavigateUrl to overwrite where the “log me out” link brings you to.


Once you save this control and refresh your page, you will have a new logout destination!

Categories: SharePoint Tags: ,

SP2010: Creating a wiki page using the OM

May 4, 2010 2 comments

SharePoint 2010 has made immense improvements over the wiki page, so much that that they are popping up all over the place in SharePoint sites.  With SharePoint Server, the home page of the team site template is a wiki page.

If you already have a standard (non-wiki) site, and want to wiki’fy the home page, you can activate the feature  Wiki Page Home Page.  This will create a pages library if one does not exist, create a wiki page in the library, and make that the site home page.


Need To Know

If you want to build your own feature to create a custom wiki page, there are a few things you need to know.

The wiki page is not a web part page

Well, technically it is, but not really.  While you can add web parts to a wiki page, it operates much differently to a web part page with zones etc.  There is one (hidden) web part zone (“wpz”) on the page, where all web parts are contained.  How they are presented on the page is all done through markup.

Know your HTML

The layout of the page is handled through html tables.  For example, the default table has two columns.  When you use the ribbon to change the layout, it creates a new table and moves the content around.  When creating your page, you should start with one of these layouts.  And above all else, make user you use fully complaint html, otherwise you may find manipulating the page in the UI will yield unexpected results.


Allow a little spacing so the user can drop elements.  If you only add web parts and don’t provide spacing in the page, it will be very hard for them to add or move elements around the page.

Web Parts

Web parts get added to the zone and to the markup.  You need to assign a guid to the web part when adding to the zone, then reference that id from the markup.  See below for the proper format of the web part reference html.

With that in mind…

lets look at creating a custom wiki page and adding it to the library.

We are doing this through a feature receiver.

The steps we are going to take are:

  1. Layout the page using HTML table.
  2. Define a couple of web parts
  3. Add web parts to web part zone
  4. Add web parts to table
  5. Create web part page in site pages library
  6. Replace wiki content with new table.
  7. Save page
  8. Eat nachos


To keep the example simple, we will assume the following (so we don’t have to manage in code).

  • A Site Pages library already exists
  • An Announcements list already exists
  • A Shared Documents library already exists
  • We’re not to concerned about error trapping (for demo purposes only!!)
    Below is the markup for our page layout.
    Wiki Page Layout
    1. <table id="layoutsTable" style="width: 100%">
    2.         <tbody>
    3.             <tr style="vertical-align: top">
    4.                 <td style="width: 66.6%">
    5.                     <div class="ms-rte-layoutszone-outer" style="width: 100%">
    6.                         <div class="ms-rte-layoutszone-inner" style="min-height: 60px; word-wrap: break-word">
    7.                             {{0}}
    8.                             <p></p>
    9.                         </div>
    10.                     </div>
    11.                 </td>
    12.                 <td style="width: 33.3%">
    13.                     <div class="ms-rte-layoutszone-outer" style="width: 100%">
    14.                         <div class="ms-rte-layoutszone-inner" style="min-height: 60px; word-wrap: break-word">
    15.                             <p>
    16.                                 <img style="margin: 5px" alt="People collaborating" src="/_layouts/images/homepageSamplePhoto.jpg" /></p>
    17.                             {{1}}
    18.                             <p></p>
    19.                         </div>
    20.                     </div>
    21.                 </td>
    22.             </tr>
    23.         </tbody>
    24.     </table>
    25.     <span id="layoutsData" style="display: none">false,false,2</span>

      This layout creates a 2-column layout similar to the default team site wiki page.
      You can see we have several tokens that we are going to replace with the markup for our web part references.
      Below is a sample of a web part referenced in the page html.
      Web Part Markup
      1. <div class='ms-rtestate-read ms-rte-wpbox' contenteditable='false'>
      2.         <div class='ms-rtestate-read 5e2446a1-fc9d-49ad-8a23-4d8e71960ff0' id='div_5e2446a1-fc9d-49ad-8a23-4d8e71960ff0'>
      3.         </div>
      4.         <div style='display: none' id='vid_5e2446a1-fc9d-49ad-8a23-4d8e71960ff0'>
      5.         </div>
      6.     </div>

    You will notice this doesn’t actually contain the web part html, just a reference to it.  The client script will move all the web parts into their correct position using the guids.

    Adding the web part to the page

    We use the SPLimitedWebPartManager to add the web part to the page as normal.

    Add web part to page
    1. private Guid AddWebPartControlToPage(SPFile wikiFile, System.Web.UI.WebControls.WebParts.WebPart wp)
    2.         {
    3.             SPLimitedWebPartManager limitedWebPartManager = wikiFile.GetLimitedWebPartManager(PersonalizationScope.Shared);
    4.             Guid storageKeyGuid = Guid.NewGuid();
    5.             string storageKeyId = StorageKeyToID(storageKeyGuid);
    6.             wp.ID = storageKeyId;
    7.             limitedWebPartManager.AddWebPart(wp, "wpz", 0);
    9.             return storageKeyGuid;
    10.         }


    Adding the web part markup to the page

    Once we format the html correctly, we inject it into the layout table.

    Add web part reference to page
    1. private void AddWebPartMarkUpToPage(Guid wpGuid, string replaceToken)
    2.         {
    3.             string wpDiv = string.Format(CultureInfo.InvariantCulture, "<div class='ms-rtestate-read ms-rte-wpbox' contentEditable='false'><div class='ms-rtestate-read {0}' id='div_{0}'></div><div style='display:none' id='vid_{0}'></div></div>", new object[] { wpGuid.ToString("D") });
    4.             wikiFullContent = wikiFullContent.Replace(replaceToken, wpDiv);
    5.         }


    Updating the Wiki Content

    Each wiki page contains one wiki field that we can reference.

    Update wiki content
    1. wikiItem[SPBuiltInFieldId.WikiField] = wikiFullContent.ToString();
    2.  wikiItem.UpdateOverwriteVersion();


    Put it all together

    So, putting all of the above together (and a little bit more) we get:

    Create Wiki Page
    1. using System;
    2. using System.Runtime.InteropServices;
    3. using System.Security.Permissions;
    4. using Microsoft.SharePoint;
    6. using Microsoft.SharePoint.WebPartPages;
    7. using System.Web.UI.WebControls.WebParts;
    8. using System.Text;
    9. using System.Globalization;
    10. using System.Reflection;
    11. using System.Xml;
    13. namespace
    14. {
    15.     [Guid("381cfa14-13a6-426a-9ee8-ecd6e7082c23")]
    16.     public class WikiPage_EventReceiver : SPFeatureReceiver
    17.     {
    18.         private string wikiFullContent = string.Empty;
    20.         public override void FeatureActivated(SPFeatureReceiverProperties properties)
    21.         {
    22.             using (SPWeb site = (SPWeb)properties.Feature.Parent)
    23.             {
    24.                 //* Define page payout
    25.                 wikiFullContent = FormatBasicWikiLayout();
    27.                 //* Add page to library
    28.                 SPList sitePages = site.Lists["Site Pages"];
    29.                 SPFolder rootFolder = sitePages.RootFolder;
    30.                 SPFile wikiPage = rootFolder.Files.Add(String.Format("{0}/{1}", rootFolder.ServerRelativeUrl, "mywikipage.aspx"), SPTemplateFileType.WikiPage);
    31.                 SPListItem wikiItem = wikiPage.Item;
    33.                 //* Define content and add
    34.                 #region Announcements
    35.                     SPList listAnnouncements = site.Lists["Announcements"];
    36.                     ListViewWebPart wpAnnouncements = new ListViewWebPart();
    37.                     wpAnnouncements.ListName = listAnnouncements.ID.ToString("B").ToUpper();
    38.                     wpAnnouncements.ViewGuid = listAnnouncements.DefaultView.ID.ToString("B").ToUpper();
    39.                     Guid wpAnnouncementsGuid = AddWebPartControlToPage(wikiPage, wpAnnouncements);
    40.                     AddWebPartMarkUpToPage(wpAnnouncementsGuid, "{{0}}");
    41.                 #endregion
    43.                 #region Shared Documents
    44.                     ListViewWebPart wpDocs = new ListViewWebPart();
    45.                     SPList listDocs = site.Lists["Shared Documents"];
    46.                     wpDocs.ListName = listDocs.ID.ToString("B").ToUpper();
    47.                     wpDocs.ViewGuid = listDocs.DefaultView.ID.ToString("B").ToUpper();
    48.                     Guid wpDocsGuid = AddWebPartControlToPage(wikiPage, wpDocs);
    49.                     AddWebPartMarkUpToPage(wpDocsGuid, "{{1}}");
    50.                 #endregion //Shared Documents
    52.                 //* Update Wiki page content and save
    53.                 wikiItem[SPBuiltInFieldId.WikiField] = wikiFullContent.ToString();
    54.                 wikiItem.UpdateOverwriteVersion();
    56.             }
    57.         }
    59.         private string FormatBasicWikiLayout()
    60.         {
    61.             StringBuilder sb = new StringBuilder();
    63.             sb.Append("<table id=\"layoutsTable\" style=\"width: 100%\">");
    64.             sb.Append("<tbody>");
    65.             sb.Append("<tr style=\"vertical-align: top\">");
    66.             sb.Append("<td style=\"width: 66.6%\">");
    67.             sb.Append("<div class=\"ms-rte-layoutszone-outer\" style=\"width: 100%\">");
    68.             sb.Append("<div class=\"ms-rte-layoutszone-inner\" style=\"min-height: 60px; word-wrap: break-word\">");
    69.             sb.Append("{{0}}");
    70.             sb.Append("{{1}}");
    71.             sb.Append("<p></p>");
    72.             sb.Append("</div>");
    73.             sb.Append("</div>");
    74.             sb.Append("</td>");
    75.             sb.Append("<td style=\"width: 33.3%\">");
    76.             sb.Append("<div class=\"ms-rte-layoutszone-outer\" style=\"width: 100%\">");
    77.             sb.Append("<div class=\"ms-rte-layoutszone-inner\" style=\"min-height: 60px; word-wrap: break-word\">");
    78.             sb.Append("<p><img style=\"margin: 5px\" alt=\"People collaborating\" src=\"/_layouts/images/homepageSamplePhoto.jpg\" /></p>");
    79.             sb.Append("<p></p>");
    80.             sb.Append("</div>");
    81.             sb.Append("</div>");
    82.             sb.Append("</td>");
    83.             sb.Append("</tr>");
    84.             sb.Append("</tbody>");
    85.             sb.Append("</table>");
    86.             sb.Append("<span id=\"layoutsData\" style=\"display: none\">false,false,2</span>");
    88.             return sb.ToString();
    89.         }
    91.         private Guid AddWebPartControlToPage(SPFile wikiFile, System.Web.UI.WebControls.WebParts.WebPart wp)
    92.         {
    93.             SPLimitedWebPartManager limitedWebPartManager = wikiFile.GetLimitedWebPartManager(PersonalizationScope.Shared);
    94.             Guid storageKeyGuid = Guid.NewGuid();
    95.             string storageKeyId = StorageKeyToID(storageKeyGuid);
    96.             wp.ID = storageKeyId;
    97.             limitedWebPartManager.AddWebPart(wp, "wpz", 0);
    99.             return storageKeyGuid;
    100.         }
    102.         private void AddWebPartMarkUpToPage(Guid wpGuid, string replaceToken)
    103.         {
    104.             string wpDiv = string.Format(CultureInfo.InvariantCulture, "<div class='ms-rtestate-read ms-rte-wpbox' contentEditable='false'><div class='ms-rtestate-read {0}' id='div_{0}'></div><div style='display:none' id='vid_{0}'></div></div>", new object[] { wpGuid.ToString("D") });
    105.             wikiFullContent = wikiFullContent.Replace(replaceToken, wpDiv);
    106.         }
    108.         public static string StorageKeyToID(Guid storageKey)
    109.         {
    110.             if (!(Guid.Empty == storageKey))
    111.             {
    112.                 return ("g_" + storageKey.ToString().Replace('-', '_'));
    113.             }
    114.             return string.Empty;
    115.         }
    116.     }
    117. }


    So what we get is a new wiki page with a couple of web parts and a picture.  Lovely jubley.



    Wrapping Up

    The wiki page is a great feature of SharePoint 2010, and using code, you can manipulate it to create your own custom pages.  I’ve shown how to create a new page, add web parts and content, then save that page to the Site Pages library.


    Many thanks to Habañero for their very useful post on the topic.

    Categories: SharePoint Tags: