
Helveticards are a set of über minimalist typographic playing cards by
designer Ryan Myers.
I love these! I designed a set of playing cards several years ago while at
university, but I certainly didn't think of doing this.
Via Laughing Squid.
Yesterday I used three things for the first time: Sass, Compass,
and Ruby. To summarize:
- I ♥ Sass
- I ♥ Compass
- I ♥ Ruby
One's own site is a great place to play with new (or in this case, not so
new) web technologies. I decided to get stuck in and manually convert the
1200 line style sheet from CSS to something a bit more awesome. This
post documents the most interesting portion of that transformation, which
involved this site's archives styles.
There's no shortage of blog posts which — like this one — provide an
introduction to Socket.IO. Many, though, were written prior to the
release of 0.7, which ushered in significant API changes. Here I'll
provide examples of server- and client-side code using APIs provided by
the current version (0.7.4 at time of writing).
A decorator is a function which takes a function and returns a function:
decorator = (fn) -> fn
Obviously, this doesn't do anything useful. It's the fact that a decorator
can return a function which behaves similarly to the function passed to it
that makes the pattern interesting. Commonly a decorator will simply wrap a
function invocation in a check of some sort:
var loginRequired = function (fn) {
return function () {
if (!user.authenticated) {
return window.location.replace('/login');
}
fn.apply(null, [].slice.apply(arguments));
};
};
The above decorator could be used to "guard" actions that only authenticated
users are permitted to perform:
var changeUsername = loginRequired(function (username) {
$.ajax({
type: 'PUT',
url: '/api/1.0/users/' + user.id,
data: {username: username}
})});
var changePassword = loginRequired(function (password) {
$.ajax({
type: 'PUT',
url: '/api/1.0/users/' + user.id,
data: {password: password}
})});
var deleteAccount = loginRequired(function () {
$.ajax({
type: 'DELETE',
url: '/api/1.0/users/' + user.id
})});
The CoffeeScript equivalent is quite a bit clearer:
changeUsername = loginRequired (username) ->
$.ajax {
type: 'PUT'
url: "/api/1.0/users/#{user.id}"
data: {username}
}
changePassword = loginRequired (password) ->
$.ajax {
type: 'PUT'
url: "/api/1.0/users/#{user.id}"
data: {password}
}
deleteAccount = loginRequired ->
$.ajax {
type: 'DELETE',
url: "/api/1.0/users/#{user.id}"
}
Decorators are commonly used in Python — which provides special syntax for
"decorating" functions — but are rarely seen in JavaScript code. This despite
the fact that JavaScript's first-class functions are ideally suited to the
task. Perhaps CoffeeScript's lighter-weight function syntax will result in
decorators making more frequent appearances in JavaScript code.
I recently came across an interesting article at wonko.com on
HTML escaping, which provoked me to rewrite Bitbucket's escape
function (invoked from within Underscore templates):
function makeSafe(text) {
return text.replace(/[&<>"'`]/g, function (chr) {
return '&#' + chr.charCodeAt(0) + ';';
});
};
This ensures that inserted content cannot escape the confines of a quoted
attribute value. Unquoted attributes are more problematic:
Unquoted attribute values are one of the single biggest XSS vectors there
is. If you don’t quote your attribute values, you’re essentially leaving the
door wide open for naughty people to inject naughty things into your HTML.
Very few escaper implementations cover all the edge cases necessary to
prevent unquoted attribute values from becoming XSS vectors.
To accommodate unquoted attribute values, the following function could be
used instead:
function makeSafe(text) {
return text.replace(/\W/g, function (chr) {
return '&#' + chr.charCodeAt(0) + ';';
});
};
I created a jsPerf test case which confirms that there's a performance
hit associated with using this more liberal regular expression. Keep in mind,
though, that if “A” takes 1ms to execute and “B” takes ten times as long,
“B” still only takes 10ms. Quite often a significant comparative speed
difference is insignificant in absolute terms; I'd argue that this is the
case here.
Want more?
Check out the archives.