Building Custom SubText Controls

In my response to Jeff Atwood, I mentioned the Technorati widget control that he is now using in lieu of Trackbacks. The Technorati widget is fairly simple to implement, but you have to be able to feed it the permalink for your post for it to be able to work. Since I already had a go at creating custom controls for use in SubText, I decided that now was a good time to see if I couldn't come up with a way to create one that has access to blog entry attributes like the permalink. For your edification, here's what I found.

First Things First

Before we walk this primrose path, lets make sure that we aren't setting ourselves up for hard times later. Create a custom Skin by copying the files from your favorite built-in Skin into a new folder in the Skins directory.

Once you do this, you'll need to let SubText know about your new skin. This is done in the Admin directory by creating a "Skins.User.config" file. The easiest way to do that is to copy the existing Skins.config file and rename your copy to "Skins.User.config". They have the same structure, but having the extra config for user skins allows the SubText team to maintain the built-in skins without messing up any customizations you might be using. Make sure that you delete all the entries for skins (except the one you copied from above). Then you can tweak the template Name and and TemplateFolder attributes (highlighted below).

Once this is done and uploaded to your SubText site, you'll see your skin listed at the bottom of the skin selection drop-down in the Admin pages (that dropdown is not sorted, so the user skins will be at the bottom). Now you can modify to your heart's content and not worry about a future upgrade nailing your customization. Also, if you really mess things up, just hit Admin and set your skin back to your old starting point.

Where Things Are

The controls you'll use to customize SubText are all in the Controls folder in your custom Skin directory.

The most daunting thing about creating custom controls is figuring out how SubText handles things. You can skip the rest of this section if you don't really care and just want to get on with creating your control.

There are a couple of quirks of SubText that can help you isolate any problems that you might encounter.

  1. SubText transfers some of the controls programmatically by grabbing subcontrols of one object and copying them to the controls collection of the parent object. This is most notable for the subcontrol brought in by the PageTemplate for the "contentregion". If you pick apart your PageTemplate.ascx, you'll see a control with an ID of "MPMain". That's where this happens. The reason for this is that SubText replaces MPMain with a different control depending on what kind of page it is trying to display. Which leads to the following problem.
  2. It isn't immediately clear which control is being pulled in by MPMain for different sections of your blog. The main page (default.aspx), for example, pulls the HomePage.ascx control. It took me a while to figure this out, but now that I have, I found that the control that functions as "MPMain" is determined by a group of <HttpHandler> elements in the web.config file (technically, MPMain can be replaced with multiple controls as you can see if you actually dig out your web.config). The HttpHandler elements in web.config describe a RegEx "pattern" attribute to apply to incoming URL requests and then a "controls" attribute that describes the control(s) used. I could have saved a lot of time if I had known this up front (say by asking members of the dev team who are actually quite helpful and would probably have responded pretty quickly, really)
  3. The classes that implement many of these controls use the specific ID of some controls to populate certain attributes--mostly Text. For example, Day.ascx can have a Literal control with an ID of "PostDesc" that is populated with the descriptive elements of a post at run time (e.g. when it was posted, if there are comments, that kind of thing). Some of these are checked for existence (like "PostDesc"), but some aren't (like "PostText"). Which are checked and which aren't makes pretty good sense, though, so I don't see that as a problem. I mean, I want to see an error if my blog is unable to display the PostText of a post.

Creating a New Control

The key feature that you need in order to leverage SubText entry information is a control class defined in SubText called CurrentEntryControl. This nifty little guy has no implementation in any of the default skins, so he's easy to overlook. The key feature he possesses is that if referenced from a control that has a blog entry associated to it, it'll let you use databinding syntax within that control to access the properties of an entry. I'm not going to say how long it took me to figure this out. Let's just be happy that I have...

The Technorati embed needs your fully qualified URL (i.e. the full-on web address to reach your post--the one you'd paste into a browser's address bar to reach just that post), so the best databind expression that I found for my purposes is:

<%# UrlEncode (Entry.FullyQualifiedUrl) %>

Believe it or not, this actually works. UrlEncode is defined in the CurrentEntryControl object along with the Entry property. Again, don't ask how long it took me to figure all this out. Just for kicks, here's the Entry class properties:

Since I'm going to want the Technorati embed to function in a couple of different page contexts, I think the easiest way to implement it is to put the script in its own control. This will be pretty simple for just the Technorati embed script:

<%@ Control Language="c#" Inherits="Subtext.Web.UI.Controls.CurrentEntryControl" %>
<script src="http://embed.technorati.com/linkcount" type="text/javascript"></script>
<a class="tr-linkcount" href="http://technorati.com/search/<%# UrlEncode (Entry.FullyQualifiedUrl) %>">View blog reactions</a>

That should be generic enough to function in any blog. I've put it together for you to download here if you want to save yourself some copy and pasting.

Placing The New Control

Now that we have the control we're going to use for Technorati's embed, you have to decide where you're going to use it. For me, I decided to use it both for posts on the blog's home page and for the individual posts themselves. After digging around, I decided that the best candidates for the new control were Day.ascx and ViewPost.ascx. Day is eventually referenced from the home page and ViewPost is referenced when displaying a post from archive (i.e. permalinked pages).

For the control to work, you'll need two things: a Register tag and the control tag. The Register tag lets the parent control know where to find your custom control. The control tag lets it know where to display it. My new ViewPost.ascx looks like this (my changes are highlighted):

Save those changes, upload to your server, and you're done. Just because I can, I included both of the modified controls in the download I referenced above. Pop all three into the Controls folder of your custom Skin and you should be good to go. Note that I pulled both of those controls out of the "Piyo" built-in skin, so it's very possible that they may differ from the controls in other skins.

22. December 2006 05:30 by Jacob | Comments (2) | Permalink

Comments

Great write-up... and this will certainly be useful for those looking to build custom controls.

Oh, and good work digging into the CurrentEntryControl stuff - Phil added that a while ago and it's quite a useful little control. I use it for a ShareThisPost control that renderes at the bottom of each post on my blog.
12/22/2006 4:17:09 PM #
Thanks Steve. I was very happy to find that control. Very useful for getting at entry properties.
12/22/2006 6:45:21 PM #

Calendar

<<  November 2014  >>
MoTuWeThFrSaSu
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

View posts in large calendar