December 2008 Entries

Creating a SubText Skin

Since 10 Volt Media created the HTML and CSS for my new skin per my request and nothing else, I’m having to create a new SubText Skin from scratch.  Fear not, this won’t be too hard of a process.  Well, it turns out, it slightly is.

Step 0.)  Have a local copy

I do not suggest doing this on a live copy of your server.  Too much goes wrong too quickly.  Do not do this on a live server.

Step 1.) XML

Head into your Subtext.Web project then to the Admin folder to find Skins.Config.  This is the file that tells the system what skins are what along with how items should be loaded.  I’ll constantly be going back to this file adding files in.

So I’ll add in a new SkinTemplate.

<SkinTemplate Name="Better Than Everyone v2" 
  TemplateFolder="BetterThanEveryone_v2">
</SkinTemplate>

Looking at other skins, you can see items can be loaded based on browser and version along with if it is being printed or is a screen.

Now I have a reference so lets create the folder.  In the SubText.Web project, we’ll go to Skins folder and for me, I’ll add the folder “BetterThanEveryone_v2”.

Step 2.) Base Files

We told the application we have the skin, now we need to get it up and working to a bare minimum.  The files will be within the “BetterThanEveryone_v2” folder.  I suggest cheating and copying from the Naked Skin (day.ascx has postcategorylist.ascx also if you do this)

These are the bare minimum files needed:

  • controls/homepage.ascx
  • controls/daycollection.ascx
  • controls/day.ascx

These are just the bare bones.  We’ll want to create a master page template to get a unified theme across all our pages.  This file will be called the PageTemplate.ascx and lives in the root level of your custom skin folder, not in controls.

Since to make my life easier and I’m borrowing base files from another skin, you’ll see a bunch of the controls that are referenced aren’t referenced yet but that isn’t that big of a deal.  We’ll add them later.  What I am going to do is comment out everything except

<dt:contentregion id="MPMain" runat="server" />

Why?  This will have the page still load.

Now not all functionality will still work.  Things won’t work still like

Step 3.)  Remembering how to code

I’m not being sarcastic here since not everything is very clear.  You’ll need to look in some CS files to know how certain things will act.  I also suggest checking out how the other skins work and look.

This is important as certain base controls work different than one another.  An instance of this is for the PreviousNext control again.  It has an attribute you can use for max text size called TextSizeLimit.  Had I not checked the base control, I would not have realized this handy addition.

Step 4.) Things to watch for

I ran into the following error when I was working with PostComment.ascx.  I used <%= instead of <%# and was given this error:

The Controls collection cannot be modified because the control contains code blocks (i.e. <% ... %>).

Also verify your search skin has the proper appearance.

Step 5.) For my skin, all needed files … I think.

controls\ArchiveDay.ascx
controls\ArchiveMonth.ascx
controls\CategoryEntryList.ascx
controls\CategoryList.ascx
controls\Day.ascx
controls\DayCollection.ascx
controls\EntryList.ascx
controls\Footer.ascx
controls\Header.ascx
controls\HomePage.ascx
controls\MyLinks.ascx
controls\PostCategoryList.ascx
controls\PostComment.ascx
controls\PreviousNext.ascx
controls\ShareThisPost.ascx
controls\SingleColumn.ascx
controls\SubtextSearch.ascx
controls\ViewPost.ascx
PageTemplate.ascx

This should be everything, some are extra but like the header and footer.  Certain items are there for base functionality, others are there to make the site usable.

Step N.) Learning SubText to make it easier

It can semi act like WordPress by using the DataBinder expression.  This means you need to know what data is coming back.

In my CategoryList.ascx, I used just this to allow me to dynamically pop in CSS classes.  This bit of code uses regular expressions to strip out non-alphanumeric characters.

<%# Regex.Replace( DataBinder.Eval(Container.DataItem, "Title").ToString().ToLower(), "[\\W]", "") %>

Step N + 1.) The next step?

The one thing I’d like to see is having SubText post back without ASP.NET controls.  This allows me not to know or care about which controls must be on the page for it to work, all I need to know is what my input control needs to be named and what fields are in the data returning.  On a “base skin”, list the data getting returned so one can do the binding rather than all the literals and labels.  Not sure how Phil Haack and company will like what I want to do but I’ll pass by the idea.

Reskinning progress

Progress after a day is pretty good.  I had to actually dive into the code a few times with SubText to fully understand how to do the skin properly as it wasn’t straight forward.  I’ll do a post but I think if you really want to do a skin, you’ll have to be able to understand ASP.Net at some level.

Here is a localhost version of the skin after a few hours of hacking.  I still need to do the comment section and properly do the right navbar.  I have to tweak the header a bit too and get the search working too.

image

After this comes me attacking SubText to add in pagination on the home page.  I also fixed, in my opinion, a bug in the PreviousNext control.  I don’t think it is coded properly, but is shouldn’t assume I have to use a worthless control on my page just for formatting.

Here is what they did:

LeftPipe.Visible = false;                            
SetNav(NextLink, entries[0]);

My fix:

if (LeftPipe != null)
    LeftPipe.Visible = false;                            
SetNav(NextLink, entries[0]);

Now the bigger issue is why that control even exists on the control and why they didn’t use FindControl instead of hard coding it in there like the other controls.  An example of what I’m talking about is this from the Header.cs:

if (null != this.FindControl("HeaderTitle"))
{
    HeaderTitle.NavigateUrl = HomeUrl;
    HeaderTitle.Text = Title;
    ControlHelper.SetTitleIfNone(HeaderTitle, "The Title Of This Blog.");
}

This code is far more defensive and doesn’t make the assumption that control is there.  However, I got away with just checking for null.  Here they are far more verbose.  To be honest, I’m not sure why they didn’t just check for null here too as they don’t set the control anywhere from FindControl also.

And yes, I’m fully aware I coded on a Friday night instead of going out.  In my defense, it is cold and very wet outside.

Coding4Fun Book!

Coding4Fun the book 

Little close up!

I'm an author!

You can buy the Coding4Fun book at Amazon and get the source code at www.c4fbook.com.  Thanks O’Reilly Publishing!

What was big and clunky is now small with LINQ

Don’t tell anyone but I’ve realized there are people smarter than me.  I’ve been slow like most getting up to speed with the new technologies, one being LINQ.  The demos I’ve seen of it have always been SQL based.  SQL and myself never really liked one another so LINQ has always been something I gave the evil eye to.  I knew it was powerful, just didn’t realize how wide spread it actually is!

So I wanted to grab a few unique images from a directory on a computer then out put them to a user.  Now the code to do this was big and could be slow but there are algorithms out there to make this faster.  Now what if there was a way to have this magically be done for me?

Old Code:

private string getUniqueFile(string[] files, 
    string currentMapPath, params string[] usedNames)
{
    string randomName = "";

    for (int i = usedNames.Length - 1; i >= 0; i--)
    {
        if (i == usedNames.Length - 1)
            randomName = getRandomFile(files, currentMapPath);

        if (randomName == usedNames[i])
            i = usedNames.Length;
    }

    return randomName;
}

Random random = new Random((int)DateTime.Now.Ticks);
private string getRandomFile(string[] files, string currentMapPath)
{
    return files[random.Next(files.Length)]
        .Remove(0, currentMapPath.Length + 1)
        .Replace("\\", "/");
}

New Code with LINQ:

private string getUniqueFile(IEnumerable<string> files, 
    string currentMapPath, params string[] usedNames)
{
    return getRandomFile(files.Except(usedNames), currentMapPath);
}

Random random = new Random((int)DateTime.Now.Ticks);
private string getRandomFile(IEnumerable<string> files, string currentMapPath)
{
    return files.ElementAt(random.Next(files.Count()))
        .Remove(0, currentMapPath.Length + 1)
        .Replace("\\", "/");
}
 

So the big thing we see here is how small the new code is.  Also how much more readable it is.  Also someone far smarter than me created the algorithm for the Except method.

As you can see, LINQ isn’t just SQL like styles, it is built into collections so use it!  It will make your life far easier.

New Skin, same ego

My friend Jeff Couturier over at 10volt Media helped re-skin my site for me.  This will be going online shortly.  It is now CSS 2.1 and XHTML 1.0 Transitional valid too!

Here is a quickie shot of it.

image

Now, on top of that, I’ll be adding in some eye candy upgrades such as using Lightbox for images, JQuery for certain things, and a new code output highlighter.  And since I love using Windows Live Writer, I’ll need the the plug-in.  I’ll also be adding in some minimizers to reduce the size of the CSS and JS.

In addition to this, I will do my best to track down some time to help add in paging support in SubText’s home page.  It took a while for me to get a dev environment again on my laptop but now that it is there, it is all night donkey kong.

But seriously, how sweet is my new logo?