Mann Software
Mann Software > SharePoint and the Office System > Posts > Wiki Processing
Wiki Processing

This is going to be a work in progress for a little bit because I'm still figuring out bits and pieces of this, and likely will be for a little while yet. I'll come back and edit this post as necessary.

This is a result of some more work I'm doing on the Community Kit for SharePoint. I'm revisiting our basic design for rendering wiki pages to see if it can be streamlined a bit, or made more versatile. At this point, I'm afraid the answer is "No" on both counts. With that said, I'll attempt to save you some time - if you want to understand how SharePoint wikis work in order to extend their base processing you can stop here. This whole article will turn out to be nothing more than an intellectual exercise. To the best of my knowledge right now, Microsoft kind of closed the door on us. We are extremely limited in the options we have for extending the default wiki functionality. Instead, we have to rip and replace to get the additional functionality we need. I'll cover that in a later blog post.

Nonetheless, it will be a fairly short article, and contains some interesting tidbits, so feel free to stick around. I'll have another post in a week or two that walks through the CKS Wiki and explains how we overcame some of the limitations in the default wiki.

Let's get started...

First, a few interesting tidbits:

  1. When you navigate to a wiki site in WSS, you are shown the "Home" page of the wiki instead of a regular default.aspx. This little bit of wizardry is accomplished by setting the (SPWeb).RootFolder.WelcomePage property for your site to a different URL, in this case the home wiki page. You can use this for any type of site. So, for example, if you wanted people to be taken to the AllItems view of a site's document library any time they visited http://site_name, you could use code similar to this:

    SPSite sitecoll = new SPSite("http://site_name");

    SPWeb site = sitecoll.OpenWeb();

    SPFolder fldr = site.RootFolder;

    fldr.WelcomePage = "Shared%20Documents/Forms/AllItems.aspx";

    fldr.Update();

    site.Update();

    site.Dispose();

    sitecoll.Dispose();

    This works for any page in the site. The default.aspx page is still available if they navigate directly to it, but it is no longer the "homepage" for the site.

  1. All wiki pages are based off of the wkpstd.aspx page in the 12\DOCUMENTEMPLATES folder. We'll cover this more later, but if you simply want to make minor changes to the wiki pages, you can edit that page. All of the usual warnings apply about editing the out of the box SharePoint files, but unfortunately, there is no way to tell the default wiki to use a different page as its template. As you'll see, we do use a different template in the enhanced wiki, but that's because we largely rip out whole portions of this process and replace them with our own.

Now let's get down to business. The process of handling wiki pages and wiki editing is remarkably simple, once you wade through it all and look at all of the moving parts. As I said, though, you have to look at this as a nice intellectual exercise because we cannot make use of much of it when we look to extend the wiki.

It all starts when we want to create a new wiki page. We can do this by either clicking the "New" button in the list or by clicking on a [[wiki link]] in an existing page, shown below:

Either way, SharePoint loads the CreateWebPage.aspx page from the Layouts directory.

CreateWebPage.aspx

The CreateWebPage page is nothing special technically, but it is part of the key to wiki functionality in SharePoint. If you're not familiar, here's what it looks like:

 

If you look at the code, you'll see a pretty standard layouts page. The important parts of the page (the Name and Wiki Content fields) are displayed with a few lines of markup:

As I said before, it's nothing to write home about, technically, at least not for the presentation so far. One interesting bit happens when you click the Create button. At that point, the click event handler comes into play. If you want to take a look at this, you need to open up the Microsoft.SharePoint.ApplicationPages from the app_bin folder of your web application (not the ...12\ISAPI folder) in Reflector. Navigate through to Microsoft.SharePoint.ApplicationPages.dll\ Microsoft.SharePoint.ApplicationPages\CreateWebPage and then take a look at the SubmitBtn_Click method.

This method basically iterates through all of the fields submitted in the form and stores them in the corresponding field of a newly created SPListItem. Nothing really special, but it shows how the values get collected from the user and stored in the wiki item. One important part to note is the call to list.RootFolder.Files.Add. This creates a new file (and the associated SPListItem) in the list. The interesting bit is the second parameter: SPTemplateFileType.WikiPage. If you follow the Add method and look at what it does, you'll see that the second parameter sets a path variable to "DocumentTemplates\wkpstd.aspx". The Add method then creates and returns (as the new file in the wiki library) a ghosted instance of this page. In other words, every wiki page in every wiki on your site uses the file located at ...12\TEMPLATE\DOCUMENTTEMPLATES\wkpstd.aspx as a template. With all of the standard caveats about editing the default SharePoint files, if you change that one file, it will reflect in every wiki page that has not been unghosted. Not too useful, perhaps, but interesting.

A few final things to note about CreateWebPage.aspx:

  1. It displays the fields from the current list via a ListFieldIterator. This means that if you add columns to your wiki list, they WILL show up on this page. Likely, that's what you wanted, but perhaps not. Anyway, it's what happens.
  2. It always creates the SPListItem in the root of the list. Folders are not supported.

At this point, we have a new file in the wiki library named with the Name supplied by the user, with basic contents drawn from wkpstd.aspx and specific contents from whatever was entered by the user in the rich text control displayed for the Wiki Content field.

Converting Wiki Markup

So far, so good, except that the text has not been converted from wiki markup to HTML. It still contains a bunch of [[page]] entries. When do they get converted to links: or ?

This is the point where wikis start to take on a little bit of a split personality. There are two conditions in which wikis can be displayed:

  1. Normal Display - all wiki markup/links are converted to properly styled HTML and displayed to an enduser: or
  2. Editing Display - all wiki markup/links is shown unconverted as regular textual markup: [[my page]] or [[a new page]].

Looking at these one at a time...

Normal Display

When the wiki page is displayed for end users, the value of the WikiContent field (the name of the field in the wiki List) is displayed via: . Inside the wiki List, the field is a simple Multiline Text field with RichText = true

Note that the FieldName attribute references "WikiField". In the UI, the field displays the name "Wiki Content" but the internal name is "WikiField" and that's what we need to reference it by. You can see this if you mouse-over the field in the List Settings page and take a look at the status bar:

Because the field in the List is simply a MultiLine Text field, the FormField tag above causes it to display as a Rich Text field in the UI.

We're now finally at the point where the wiki markup gets translated to HTML. It happens in the RenderFieldForDisplay method of the Microsoft.SharePoint.WebControls.RichTextField class. The method itself is pretty short, the meat of it for wikis being the following three lines:

output.Write("<div class=\"ms-wikicontent\">");

output.Write(field.GetFieldValueAsHtml(this.ItemFieldValue, base.ListItem));

output.Write("<p></p></div>");

The call to GetFieldValueAsHtml will eventually make a call to Microsoft.SharePoint.SPFieldMultiLineText.ProcessWikiLinks (assuming that WikiLinking is set to true for the RichTextField, which it is in our case). ProcessWikiLinks iterates through the ForwardLinks collection of the SPListItem that is our wiki page and converts the wiki links [[my page]] to this HTML if the target page already exists:

<a id="ctl00_PlaceHolderLeftActions_RecentChanges_ctl00_RecentChangesIterator_ctl01_RecentChange" class="ms-navitem" href="/wsswiki/Wiki%20Pages/my%20page.aspx">my page</a>

And this HTML if it does not:

<div><a class=ms-missinglink href="http://moss1/wsswiki/_layouts/CreateWebPage.aspx?List={0971da62%2Da81d%2D4879%2Da11b%2D17bb362f76bb}&RootFolderUrl=%2Fwsswiki%2FWiki%20Pages&Name=a%20new%20page" title="a new page - click to define topic">a new page</a></div></div><p></p></div>

The latter snippet, as you can see, decorates the anchor tag with a class attribute that is responsible for the on-screen display that indicates the wiki page does not yet exist. Notice also the href attribute is a call to CreateWebPage.aspx. This starts the process for a new page, which we covered at the top of this article.

Notice that the text is converted for every page load. It is not converted and stored. For wiki links, this is preferred as pages can be added or deleted at any time, so we need to process the links based upon the current status of the pages. In the CKS Enhanced Wiki, we add a lot more markup parsing which would be expensive to do for every page load, so we handle that slightly differently. We'll cover that in another post.

Editing Display

After all of the above, the editing display is easy. As we now know, our Wiki Content (WikiField) is just a multi-line text field in SharePoint. In the edit view, the standard EditForm.aspx page simply renders this as a regular RichTextField with the Rich Text Editor toolbar in place. Nothing happens to the text because it is stored in its raw form - i.e. with the wiki markup intact. We don't need to convert the text, as mentioned above, because it is stored in the unconverted state. So, displaying the wiki field for editing is no different thatn showing any other SharePoint field for editing.

There is one minor element that does get added specifically for wiki fields: the little instructions blurb that shows up below the field:

This is handled in the Microsoft.SharePoint.WebControls.RichTextField.RenderFieldForInput method. After all of the other processing has happened, the following lines add this text:

if (field.WikiLinking)

{

output.Write("<span class=ms-formdescription>");

output.Write(SPResource.GetString("WikiLinkInstructions", new object[0]));

output.Write("</span>");

}

As you can see, the text itself is taken from a resource file. The RenderFieldForInput method also handles adding the proper JavaScript to the page to handle the RichText editor functionality by making a call to the SPUtility.TextAreaToRichTextClientScript method.

That's it for editing.

One Other Point

One more thing that it is important to know is that the default wiki list limits the number of RichText fields it can contain to just one. This means that it is not possible to have >1 wiki field on an item.

Conclusion

So there you have it, a little waltz through the default SharePoint wiki to show how it handles converting wiki markup to HTML and the creation of pages. All in all, it's pretty basic stuff. In a later post, I'll cover how we change this process to overcome some internal designations and also add support for a lot more wiki markup and some other functionality.

Dave

Comments

There are no comments yet for this post.
SharePoint Server MVP Community Kit for SharePoint Philly Office Geeks ISPA