Custom Textile Tags For Great Justice

Wherein our hero recounts the tale of the custom textile tag that saved the world. Or at least saved our humble hero some typing.

fig. 1.1 | elem-typo-style.png

Taking some inspiration (and code) from the quirky but lovable _why’s original post on adding yer custom blocks to RedCloth and the inimitable Geoff Grosenbach’s foray into the world of custom textile figure tags, we’ve build a custom tag (or prefix) for this blog’s own figures, like figure-1-1) there on the right.

RedCloth’s textile implementation uses some simple metaprogramming to create its own tags, which allows you to (more or less) easily create new tags to suit your own needs. The basic formula is: write a textile_#{ tag } method, where tag is the name of the tag you want to create. This method takes four arguments, tag, atts, cite and content, which are parsed from the textile by the RedCloth engine.

For our purposes, we’re only concerned with content and atts, so I’ll leave the rest as an exercise for the gentle reader. The html we’re trying to create looks like this:

<div class="img" id="figure-1-1">
  <a class="fig" href="/images/image.jpb">
    <img src="/images/thumbs/image.jpg" alt="Figure 1.1" />
  </a>
  <p>Figure 1.1</p>
</div>

The tag we want to use to create it looks like this:

fig. 1.1 | image.jpg

That’s quite a bit shorter and more elegant. Jumping right in to the good stuff, the method definition for our new tag looks like this:

def textile_fig(tag, atts, cite, content)
  span_class = "img "
  if atts =~ /class="([^\"]+)"/
    span_class += $1
  end
  (figure_number, img_url) = content.split("|").map { |w| w.strip }
  figure_name = "Figure #{figure_number}"
  figure_id = "figure-#{figure_number}".tr(".", "-")

  %{
  <div class="#{span_class}" id="#{figure_id}">
    <a class="fig" href="/images/#{img_url}">
      <img src="/images/thumbs/#{img_url}" alt="#{figure_name}" />
    </a>
    <p>#{figure_name}</p>
  </div>
  }
end

Let’s break that down.

span_class = "img "
if atts =~ /class="([^\"]+)"/
  span_class += $1
end

This adds any classes in atts (in the form of class="foo") to the base class, img.

(figure_number, img_url) = content.split("|").map { |w| w.strip }
figure_name = "Figure #{figure_number}"
figure_id = "figure-#{figure_number}".tr(".", "-")

This breaks “fig 1.1 | image.jpg” down into two parts by splitting on the “|” and then normalizes them a bit to be used later.

Finally, the relevant parts are jammed into the html prototype and spit back as the method’s return value for insertion into your textile document (and for great justice, of course).

fig. 1.2 | ReinH-07.png

A later post might show the way __END__, DATA and if __FILE__ == $PROGRAM_NAME were used with the TextMate Ruby Bundle’s &#x2318;R command to preview the output of the textile tag as it was being written for a faster workflow or the jQuery used to activate the thumbnail’s hover effect while an inline link like figure-1-2) is hovered. But I wouldn’t hold your breath.