Common Dream

Add Features to Your Elements With Featurette

In my years of working with JavaScript I’ve seen kind of a natural progression to how I’ve scripted elements within pages. In the beginning, I just kind of wrote some javascript, put it in a function, and attached it with an event on the element itself. So around 2001 or so my scripts looked a lot like this:

1
2
3
4
5
6
<script type="text/javascript">
  function handleClick() {
    alert("Stop clicking me!");
  }
</script>
<a href="#" onclick="handleClick(); return false;">Click Me</a>

As time moved on the idea of unobtrusive JavaScript took hold. The idea was that we shouldn’t use those fancy onclick attributes since they dirtied up our markup, but should instead attach the events. I used Prototype in those days, so my code looked something like this:

1
2
3
4
5
6
7
8
9
10
<a id="click-me" href="#">Click Me</a>

<!-- this code was usually down at the bottom of the body of the document -->
<script type="text/javascript">
  function handleClick() {
    alert("Stop clicking me!");
  }

  $('click-me').observe('click', handleClick);
</script>

That was probably 2006 onward for me.

In general, going unobtrusive cleaned up my document a bit, but there was still a mess of code in the document, it was just hidden elsewhere. Within the past year or so the way I handled that was to switch to a series of backing objects that I included in external script files. I’d instantiate those objects in a script tag in my document, but all the rest of the code would be stored in scripts outside the document. At that point, I had moved on to using jQuery. My code started looking something like this:

page.html
1
2
3
4
5
<a id="click-me" href="#">Click Me</a>

<script type="text/javascript">
  new ClickMeThingy("click-me");
</script>
script.js
1
2
3
4
5
6
var ClickMeThingy = function(id) {
  $('#click-me').click(function(e) {
    e.preventDefault();
    alert("Stop clicking me!");
  });
};

This example is crazy simple, but hopefully you get the idea. Using objects was the right direction, I think, because they gave me a nice bundle for a feature or page’s functionality, but something still felt wrong.

In our latest design refresh of Treehouse, I started using CoffeeScript rather than JavaScript, and I started bypassing the script tag in the document and instead just detecting elements that should have features attached to them. It looked something like this:

1
<a class="click-me" href="#">Click Me</a>
1
2
3
4
5
6
7
8
9
10
11
12
class ClickMeThingy
  @detect: () ->
    $('.click-me').each (index, element) ->
      new ClickMeThingy(element)

  constructor: (element) ->
    $(element).click (e) ->
      e.preventDefault()
      alert("Stop clicking me!")

$ ->
  ClickMeThingy.detect()

I liked this technique when it was for code that I really wanted to apply to every page, but there’s a tradeoff with the technique - it really stinks if you’re detecting a lot of different types of features because a lot of times you’ll call the detection code and nothing matches. That problem lead me to write Featurette.

The idea behind Featurette is that you define new classes representing features you want to attach to elements and register them. Any time you want to apply a feature to an element in your document you give it a class of featurette and add the data-featurette attribute with the name of the feature you want to add. Let’s look at how the ClickMeThingy example above would be implemented with Featurette.

1
<a class="featurette" data-featurette="click-me" href="#">Click Me</a>
1
2
3
4
5
6
7
class ClickMeThingy
  constructor: (element) ->
    $(element).click (e) ->
      e.preventDefault()
      alert("Stop clicking me!")

Featurette.register("click-me", ClickMeThingy)

When the document loads up, Featurette searches for all elements with the featurette class and instantiates registered objects based on the data-featurette attribute. Using a class name to find elements that need features attached ensures that performance stays super fast, thanks to the DOM’s getElementsByClassName function. It’s a little more markup than is ideal, but it keeps things fast and it gets rid of the script tags that plagued my older solutions and the extra document searches that came with my original attempt at detecting when code should be attached to elements.

We’ve just started using Featurette with Treehouse, but so far it’s working great. I’d love to hear what you think of it! If you find any issues, please report them in the GitHub issue tracker, and if you have any questions feel free to email me or tweet at me.

Blogging With Octopress

I’ve been meaning to switch my blog over to Octopress since sometime last year, but haven’t ever taken the leap. Today, though, I figured I’d stop putting it off and start taking advantage of the beautiful code display and much more developer friendly workflow. I’m super glad that I did.

If you’re interested in trying out Octopress yourself, go check out the docs at http://octopress.org.

Disabling and Re-Enabling Text Selection

A few days ago I was working on a little bit of drag code for a web page, and realized that there weren’t too many clearly defined solutions for disabling and re-enabling text selection in browsers, so I went ahead and wrote up a solution. Here it is!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class TextSelection
  @returnFalse = -> false

  @disable = ->
    $('body').css
      "-moz-user-select": "none"
      "-webkit-user-select": "none"
      "-ms-user-select": "none"
    $(document).mousedown -> @returnFalse
    if $.browser.msie or $.browser.opera
      $('body').find(":not(input)").attr("unselectable", "on")

  @enable = ->
    $('body').css
      "-moz-user-select": "auto"
      "-webkit-user-select": "auto"
      "-ms-user-select": "auto"
    if $.browser.msie or $.browser.opera
      $('body').find(":not(input)").attr("unselectable", "off")

It has been tested across all major browsers, down to IE6 and including Opera. I’ve also tested it with iOS4 and iOS5. You can still select text with it on Android, at least whatever version of Android my Kindle Fire is running, but my purpose for this was primarily to disable selection while dragging around the page, and you have to click and hold to get selection to happen on the Kindle Fire anyway, so I don’t think it’s a big deal.

The script does require jQuery to work, and in case the code above looks crazy to you, it’s written in CoffeeScript. Don’t worry, here’s a version that’s converted to JavaScript if that’s more your thing. Let’s run through the script right quick:

1
@returnFalse = -> false

This is just defining a simple function that returns false. I realized a couple of the techniques I was using required callbacks that just return false, so I figured it made sense to factor out.

So now for the disable method:

1
2
3
4
$('body').css
  "-moz-user-select": "none"
  "-webkit-user-select": "none"
  "-ms-user-select": "none"

user-select isn’t part of any CSS spec, but it’s been added by Firefox, Webkit, and IE, so I wouldn’t be suprised for it to make it in there soon. It’s by far the cleanest way to disable selection in my opinion. You’ll notice all the vendor prefix there. I decided not to include the non-prefixed version, since there’s no spec for the behavior anyway.

As a side note, I think embedded objects like this is one place where CoffeeScript really shines. No commas or curly braces - it starts to almost look line CSS inline in the script rather than code.

Adding user-select handles things for most browsers, but we do still need to use one other technique to hit every browser. user-select is only supported in Internet Explorer version 10, which isn’t fully released yet. Also, Opera still doesn’t have support for user-select. Fortunately, back in the old days both IE and Opera included an attribute on elements to disable text selection, the aptly named unselectable attribute. We can use jQuery to set the attribute of that value to on for the whole page, and that’ll take care of it.

1
$('*').attr("unselectable", "on")

We’re matching everything in the document and making it unselectable. It’s really straightforward, but unfortunately * is also about one of the worst performing selectors we could use. That’s why we go ahead and use browser detection to try and limit usage on it to IE and Opera, the browsers that need that technique.

1
2
if $.browser.msie or $.browser.opera
  $('*').attr("unselectable", "on")

That’s it! We’ve now got text selection disabled across the entire document. You can call the disable method with TextSelection.disable(). I won’t run through the enable method, because it’s basically just the opposite of the disable method, and I’m pretty sure you’ve got the idea of how it works.

It can be a pain to get things like this working across all browsers, but it’s gotten more and more easy to do lately, since so many browsers are becoming so similar in their implementation of features. I was amazed that something like user-select that isn’t even part of a CSS spec was supported across most browsers as well as it is.

Where the Magic Is Supposed to Happen

 So, as we begin 1991, let’s really look at those weekly box office
 figures and hear what the numbers are saying… what I believe they
 are telling us is to stop concentrating so much on what happens in
 that little room where the tickets are sold and instead concentrate
 on what happens in the big room where the lights dim and the magic is
 supposed to happen.

Jeffrey Katzenberg, Some Thoughts on our Business, from Letters of Note

Tconsole 1.0 Is Out!

I’ve been using a little project I spiked out called tconsole for a couple of months now, so I figured I should mark the gem as 1.0 and get on with things. tconsole is a command line tool that helps me and other Rails developers test more efficiently by not requiring us to reload our environment every time we run a test. tconsole has some helpful features like allowing us to easily test single test files, or even specific tests.

Interested in tconsole? Check it out on GitHub!

Figuring Out Where a File Was Required

I’ve been working on test performance a lot lately. Tonight I ran into a strange issue and needed to figure out where a file was being required from. That can be pretty tricky in a Rails app, since often files are being autoloaded.

I used this code up at the top of the file in question to figure out where it was loaded from:

1
puts caller.join("\n")

When the file was loaded by the Rails autoload code I got a nice looking stack trace of where execution was at that point in time, and all I had to do was look back to the first place where my code was referenced to figure out what was happening.

Be Sure to Include a Rating for Gravatar

When we launched Treehouse, we decided to use Gravatar for user avatars on profile pages. Here’s my profile page, for example. When we rolled it out I copied the Gravatar code on their site and ported it to Ruby. It was a pretty simple task.

Unfortunately, I heard reports from a few users after launch that their profiles werent showing up correctly, and were instead showing the fallback image. I tested their images on some other sites, and things showed up great. I was stumped.

After more trial and error I figured out that the problem was ratings. Gravatar has a rating system for avatars, so that you don’t show an avatar that’s a bit racier than would be acceptable for your audience. By default, they set the rating to G, so no images that are rated above a G rating will be returned. Our users that were having the issue all had a PG rating on their avatars. I’m not sure why they were rated PG because they were just pictures of the peoples’ faces, but that’s what was happening.

Adding that rating parameter fixed things, though. Heres the code we use for grabbing Gravatar image urls:

1
2
3
4
5
6
7
8
9
require digest/md5

class Gravatar
  def self.url(email, default, size = 200)
    email = email.downcase
    hash = Digest::MD5.hexdigest(email)
    "http://www.gravatar.com/avatar/#{hash}?s=#{size}&d=#{default}&r=pg"
  end
end

How I GTD With Email

I read David Allen’s Getting Things Done quite a while back when I was younger, worked at an insurance company, had VP in my title and thought that was awesome, and felt like more than anything else I just needed to get things done. Now, six or so years later, my mind summarizes the book something like this:

  1. Keep a list on paper. Add things to it as you realize you need to do them.
  2. Double check that list every day. If you can knock something out in a couple of minutes, go ahead and knock it out.
  3. Work back through the list again, from highest priority to lowest.

Over the past month, since getting an iPhone 4S, Siri has pretty much rocked my world and I’ve been using the Reminders app a ton since I can easily record things I need to do by just saying them. iCloud syncs Reminders to my Mac as well, so I use Reminders a good bit there too (although I’d love to pay for a Reminders app that’s more like the iPhone one, but for Mac). In general I use the rules above to handle what I’m up to and what I need to do, but track it in Reminders instead of on paper.

I’ve always had a problem with email, though. I get a decent amount of email, and have been getting about twice what I used to consider a lot since Treehouse launched. I’ve typically considered my email inbox a sort of To Do list and worked through things, archiving them when I’m done with them, but with super high email volumes that hasn’t been nearly as possible. I realized recently that it’s taking me a week or more at times to get back to some messages, and I hate the idea of being that slow to respond because more than anything I try to make people the most important thing about what I do. That called for a new process.

For the past week or so I’ve been doing is processing emails with my normal GTD method. Here’s how it works:

  1. Read a new email.
  2. If I can handle the email in a couple of minutes, I knock it out.
  3. If I can’t handle the email in a couple of minutes, I let the person on the other side know it’ll be a bit before I can do whatever it is I need to do to handle the email, and then log the email in my Reminders list in iCal and put the email in a folder called Later.
  4. Whenever I finish handling that email, I search for it in my Later folder, respond to the person if needed, and then archive the email.

Whenever I add an email based reminder to my list I make sure I include some text that’ll make it easy to search for the email and remove it from the Later folder.

This probably isn’t that unique of a workflow, but it has worked well for me over the past week. I personally feel a lot better about a crowded list of short To Do items than a crowded email inbox with paragraphs and paragraphs of information to deal with. I’ve been able to keep my inbox pretty clear and it has helped me make sure I’m responding to everyone who emails to me in a pretty timely manner.

Cellular Automata Method for Generating Random Cave-Like Levels

C_e_l_l_u_l_a_r A_u_t_o_m_a_t_a M_e_t_h_o_d f_o_r G_e_n_e_r_a_t_i_n_g R_a_n_d_o_m C_a_v_e-L_i_k_e _L_e_v_e_l_s Ive always been super interested in cellular automata and thought it was interesting to see such a practical use case for them.