-
"Being able to go back and fix your mistakes is not the same as being forgiven for them. Maybe that’s what all those storybooks were trying to tell us." Lovely.
-
"If you’re an adult who’s at a place in life where you need to pretend you’re interested in people whom you are not actually interested in, then “fake following” should be more than adequate for your needs. But, if you’re here to actually read things and to enjoy the thoughts, photos, and opinions of actual people who have good and bad streaks, it wouldn’t hurt to have an easy way to hit “snooze” for a while." Merlin Mann is very sensible.
-
"It seems to me that Tim and the nameless characters of the epilogue represent archetypes of some kind. They don’t stand in for every man and woman, certainly, but they’re emblematic of a certain kind of dysfunctional relationship, one where “I’ll protect you” turns into “I’ll control you.”" A smart, sharp reading of Braid, that understands its gameiness.
-
"The mouse is a continuous pointing device; the finger is discontinuous. That’s a profound difference that I wish I were able to clearly understand and explain." PPK on how MobileSafari responds to Javascript's mouse actions.
-
"I think, in these fleshed out circumstances, an RPG could be the most remarkable place for getting to grips with matters like abortion and euthanasia. I think _because_ they’re the sorts of subjects it’s completely pointless to talk about in the pub, because it inevitably descends into people entrenching themselves in their currently held position and then hurling stones at the other side, that the RPG would be a space in which the emphasis of thought and consideration would be squarely on you." John Walker on the problem with BioWare's attitude to morality, and some potential solutions.
-
"Opentape is a free, open-source package that lets you make and host your own mixtapes on the web. Upload songs (via web or FTP), reorder, rename, customize the style, and share what you like on other sites with an embeddable player."
-
"I've heard that Japanese developers, who have traditionally held American game development in low esteem, have a great deal of respect for Bungie, and you can understand why. Bungie has done for shooters what Nintendo did for platformers: they've turned the visceral joys control and motion into the centerpiece of the game."
-
"Thomas Finchum, an American diver competing in Beijing, describes the view from the 10-meter platform at the Water Cube." Incredible, interactive panorama from the top board in the Water Cube.
-
"Greebles are the parts that "look cool, but don't actually do anything". There's an entire discipline here composed of special effects artists and asset designers working to hide the plywood spaceships and simple game world polygons beneath an encrusted surface texture." And this is the trick to make the little bits look like part of a whole. Lovely talk from Mike at UXWeek.
-
"One of the new features of FriendFeed (a Twitter-like thingie) is "fake following". That means you can friend someone but you don't see their updates… It's one of the few new social features I've seen that makes being online buddies with someone manageable and doesn't just make being social a game or competition."
-
An interesting series of concept images of what context-aware, mobile search and data-diving tools might look like. Some neat thinking around transparency and context.
-
"I wanted to take portraits of people that would reveal a hidden part of their character. So I had them play videogames."
-
"Why did Weight Watchers work so well? For a really fascinating reason: because it isn't a normal diet. It's something more. Something fun. It's an RPG." Of course. Fantastic deconstruction from Clive Thompson.
-
Braid papercraft. Delightful.
-
Eesh. Tetris in 500 bytes of Javscript and HTML. Yes, they're obfuscated and unpleasant, but wow, etcetera.
jQuery: passing elements to event handlers
03 August 2007
It’s fairly common practice in jQuery to bind events to a quick anonymous function that performs the action you desire. But how do you bind an event to a non-anonymous function – something that you’ve already extracted into a function so as to avoid reptition? I learned this one the hard way, and thought it was worth sharing.
I was working on some jQuery to apply to some legacy HTML at work, and was fiddling around to see if our goal was possible.
I was working on a “springy” archive menu. There are some headers and some lists; the lists are hidden on pageload, and when you click on a header, the subsequent list (ie the archive for that year) opens. Many lists can be open or closed at once. In addition, we toggle a class on the header (rather than the header link, which is there purely out of legacy code for now) to change an image, indicating that it’s open.
Here’s my proof of concept code – my first working version to demonstrate how this functionality would work.
$(document).ready(function() {
var headlinks = $("div.container h3 a");
for (var i=0; i < headlinks.length; i++) {
$(headlinks[i]).bind("click", function() {
$(this).parent().next().toggle();
$(this).parent().toggleClass("open");
});
$(headlinks[i]).parent().next().toggle();
$(headlinks[i]).parent().toggleClass("open");
};
toggleArchiveLinks(headlinks[0]);
$(headlinks[0]).parent().next().toggle();
$(headlinks[0]).parent().toggleClass("open");
});
Now we've got the code working, it's time to refactor. There's a lot of repetition going on - three instances of that "toggle visibility and toggle class" behaviour, so let's pull that out into a function:
function toggleArchiveLinks(element) {
$(element).parent().next().toggle();
$(element).parent().toggleClass("open");
return false;
}
Much better. Unfortunately, we can't replace our anonymous function within that bind
directive with this. I initially thought you could bind "click" to toggleArchiveLinks(this)
. But that doesn't work, because in the context of events, what gets passed out to another function is the event object itself. (I think it works fine in the anonymous object due to the way things are scoped).
But it's a bit ugly to refactor some, but not all of the code. After looking at the jQuery docs for bind
, it turns out that there's a third parameter you can pass in: a data object. This is made available to a handler function. So that means we can pass information about the element we want to toggle to a handler event. We write our new bind directive like this:
$(headlinks[i]).bind("click", {element: headlinks[i]}, handleToggleEvent);
That object in the middle will be made available to a new function handleToggleEvent
. (We could, of course, pass as many key/value pairs as we wanted to to the function). We also need to write handleToggleEvent
. That function looks like this:
function handleToggleEvent(event) {
toggleArchiveLinks(event.data.element);
event.preventDefault();
}
The function accepts an event as a parameter, and the object/hash from our bind
statement is available as event.data
. We're then free to call toggleArchiveLinks
on the element of our choosing. Finally, we have to call event.preventDefault
in order to stop the event propagating any further. If we don't do this, the bound behaviour will happen, and then the link will click through as normal. return false;
won't work here, because we're actually dealing with the event itself, not just an anonymous function.
So we've now managed to refactor some repetitive code and call it from a bind
statement. Our final jQuery script looks like this:
$(document).ready(function() {
var headlinks = $("div.container h3 a");
for (var i=0; i < headlinks.length; i++) {
$(headlinks[i]).bind("click", {element: headlinks[i]}, handleToggleEvent);
toggleArchiveLinks(headlinks[i]);
};
toggleArchiveLinks(headlinks[0]);
});
function toggleArchiveLinks(element) {
$(element).parent().next().toggle();
$(element).parent().toggleClass("open");
return false;
}
function handleToggleEvent(event) {
toggleArchiveLinks(event.data.element);
event.preventDefault();
}
Which is much better, I think.
CSS Redundancy Checker: jQuery edition
11 July 2007
So the CSS Redundnacy Checker has done a fair bit of traffic recently. Wow, etc. I hope it’s turning out to be useful. I’ve committed a few minor fixes, and there could be more improvements to come thanks to some useful feedback. I’ll be getting in touch with people about it over the next few days, I hope.
When I sat down to write the tool, I knew it would only be possible with a decent CSS parser (because you need a proper parser, and can’t do this with regex magic). The two that leaped to mind immediately were Hpricot and jQuery. In the end, I went with the former, because a commandline script seemed a good starting point, and something that could be built open in many ways.
In the comments thread, Tom at WorkingIdea alerted me to his jQuery-powered CSS Redundancy checker. It’s a Greasemonkey script with built-in jQuery that dumps redundant classes either to the Firebug console or to a Javascript console if you don’t have Firebug. Sounds like it might not be quite as fast as the Ruby one – or as flexible – but if you don’t have Ruby installed or just want to run something from your browser, it’s a great idea. And it’s the same principle as my script – harnessing somebody else’s CSS parser in a really simple way.
So now there are two ways into the same usefulness. It only seemed fair to link this up, given what a neat solution it is – and how close I came to doing it myself.
(Incidentally, the reason there’s not an online version of my script is because it is a slow process, and I’d have to write some kind of queueing solution on the frontend, and it could all get messy fast. It’s not for that. Get it yourself, run it locally; there are instructions on setting it up for people who don’t have Ruby in the README).
It’s a strong title for a post, I know, but having discovered that two friends didn’t know this at last night’s LRUG, I wanted to share it.
Let’s put this in bold for impact.
When you add <%= javascript_include_tag :defaults %>
to the top of your Rails layout, you’re adding 146kb to your page load.
And, being Javascript, that all loads serially. This is slowing page load down a lot.
Now, I’m sure if you’re building a whizz-bang AJAX app you need all that. But I reckon a lot of Rails projects don’t use anywhere near all that. So throw some out!
The Scriptaculous libraries are quite big: dragdrop.js
is 30kb, controls.js
is 29kb, effects.js
is 34kb. If you don’t need that lot, get rid of it. prototype.js
alone is 56kb. The case for the Prototype library is easier to make… but if all you’re doing is some simple DOM scripting – show/hide, for instance, do you really need 56kb of library functions to do it? Or can you do it in < 10kb with some home-made functions? If so, strongly consider doing that. And if you’re not using any Javascript in your application… why have you get any of it in there? It can all go – that’ll speed page load up no end!
I’m not saying there’s no place for this stuff – there is. Should it be included in Rails Core? Absolutely. I just don’t think that it should be called the “default” option; <%= javascript_include_tag :all %>
would make a lot more sense. And by sticking it into the basic scaffolding layout, it becomes a part of many people’s first experience with Rails – and they assume it’s default behaviour. And so I also think it should be left out of scaffolding – perhaps replaced with <%= javascript_include_tag "prototype", "application" %>
at the least.
User experience, usability, and accessibility aren’t just about the content or code of the page; they’re about how the user experiences the page. If it takes an age to load, it makes the app less usable. If you’ve got huge page size, you’re excluding anyone on a slow connection. So next time you’re skeletoning out a Rails app, take a moment to think if you really need any Javascript. If you don’t, <%= javascript_include_tag :defaults %>
can go straight in the bin. Then, when you come to progressively enhance your app at the end with Javascript (which is, let’s face it, how you should be doing it), you can include only the files you need – and keep your users happy at the same time.