So I have a modestly popular Safari extension that enables keyword search from the address bar. This extension relies on an event called beforeNavigate, which is triggered whenever a user tries to load a url. This event has been available for extensions since Safari 5.1.
The event is kind of tricky to work with for what I’m trying to do, since it is triggered after Safari has tried to parse whatever text was entered in the address bar into a URL. This means that when a user types g monkey, the event provides the URL http://g%20monkey/, making parsing harder than it should be, especially for the default keywordless search (which is Googles “I am feeling lucky”). In addition the search phrase a user enters cannot contain a colon symbol, as that causes Safari to show an error page before the event is triggered.
These are minor annoyances but work-aroundable. The real problem is Safari 5.2, which unifies the search bar and the address bar into a single text field that is similar to (but much less capable than) the Omnibar in Chrome. What now happens is that anything that doesn’t look like a URL is turned into a web search, before the beforeNavigate event is triggered. That means that the data sent along with the event looks like http://google.com?q=g%20monkey. This could still be parseable by the extension, but it is impossible to know whether the user entered it as a keyword search or actually want to search google for “g monkey”.
Needless to say this regression makes my extension broken and useless in Safari 5.2. I have reported this issue to Apple, and suggested three possible ways to fix it, in order of preference:
Fingers are crossed.
Lion is out, and with it Safari 5.1. This release of Safari disables one of my must-have plugins, Keywurl. This plugin uses SIMBL to hack into the Safari binary and provides keyword search from the address bar. I have become utterly dependent on this, and feel really crippled when it doesn’t work.
Safari 5.1 contains some cool new stuff for extension developers, however, one of the new features being the SafariBeforeNavigate event. This event is triggered before any page is loaded, and can be used to implement the same functionality as Keywurl.
Accordingly, I did the only right thing, and created a Safari extension that performs keyword search. At the moment there is no interface for setting it up, so you’ll have to edit the code and install the extension via the Extension Builder using your own developer certificate, but that will probably change in the future. Installation instructions are available on GitHub.
Update: The extension now has an integrated editor, accessible on right-click.
So I made a simple javascript-thing for creating iOS-style flickable image galleries on smartphones and tablets and such. You can view a demo on flickable.aurlien.net (works in desktop browser too, although it isn’t quite practical), and download the source code on GitHub. It is quite slick, has no dependencies, and uses CSS3 3d-transforms for optimal performance. Check it out.
…without using arguments.callee!
I have read several “simple” introductions to the Y combinator (some of which are truly excellent), but I don’t know if I’ll ever manage to wrap my head completely around it, and it seems a bit verbose in use (at least in Javascript). It is a very cool concept though, and I decided to try implementing something similar (but possibly simpler) on my own. I managed to do this by using Javascript-specific stuff, specifically dicking around with arguments.
Technically, what I came up with is not exactly the same as the Y combinator, but its purpose is the same: To allow anonymous recursion. I’ve taken the liberty of calling it “the Z combinator” and it looks something like this:
function Z(func) {
var fun = function() {
return func.apply(null, [fun].concat([].slice.apply(arguments)));
};
return fun;
}
var fact = Z(function(rec, i) {
if (i === 0) {
return 1;
} else {
return i * rec(i-1);
}
});
fact(4); //24
// It can also be inlined:
Z(function(rec, i) { return i===0 ? 1 : i * rec(i-1); })(4); // 24
The Z combinator takes a function as an argument, and returns a new function that wraps the original and prepends itself to the argument list (if that makes any kind of sense). When recursing, the function should use call first parameter (rec, in this case) instead of calling itself by name. Thus, anonymous recursion! Maybe not very useful, but it was fun to do.
22 seconds from outside work yesterday morning.
In my last project at work, I had to work with fairly large data structures in Javascript. More than once I needed to sort data stored in Javascript objects. Javascript objects are by definition unsorted, so naturally there is no built-in way of doing this. All browsers, however, keep objects in the order that properties were added, so I decided to write a comprehensive sorting function.
This function will sort a Javascript object by key, value or predicate function, by transforming it to a temporary array and using the built-in Array.sort() on that. Here it is in all its glory:
sortObj = function(obj, type, caseSensitive) {
var temp_array = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (!caseSensitive) {
key = (key['toLowerCase'] ? key.toLowerCase() : key);
}
temp_array.push(key);
}
}
if (typeof type === 'function') {
temp_array.sort(type);
} else if (type === 'value') {
temp_array.sort(function(a,b) {
var x = obj[a];
var y = obj[b];
if (!caseSensitive) {
x = (x['toLowerCase'] ? x.toLowerCase() : x);
y = (y['toLowerCase'] ? y.toLowerCase() : y);
}
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
} else {
temp_array.sort();
}
var temp_obj = {};
for (var i=0; i<temp_array.length; i++) {
temp_obj[temp_array[i]] = obj[temp_array[i]];
}
return temp_obj;
};
And here are a couple of usage examples:
var obj = {c:'b',a:'c',b:'a'};
// Sort by key
sortObj(obj);
// {a:'c',b:'a',c:'b'}
// Sort by value
sortObj(obj, 'value');
// {b:'a',c:'b',a:'c'}
// Sort by predicate function
sortObj(obj, function(a,b) {
var data = {a:2,b:1,c:3};
var x = data[a];
var y = data[b];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
// {b:'a',a:'c':c:'a'}
If you want the sort to be case-sensitive, set the second parameter of .sort() to true.
As always when extending Object.prototype, don’t forget to use hasOwnProperty when iterating over the object. But you’re of course doing that already, right?
Update: Be careful using this with Chrome. If your object has both numbers and strings as keys, Chrome will sort the object with the number-keys first, even when sorting by value. Example:
var obj = {a:2, b:1, 1:'a'};
obj.sort('value'); // Other browsers: {b:1, a:2, 1:'a'}, Chrome: {1:'a', b:1, a:2}
A sincere THANK YOU to all those who have given color.aurlien.net the upwards-ponting thumb on StumbleUpon — I’ve had over 25.000 visitors in a month, which is awesome. Thanks, guys!
I recently had use for a map()-function while writing Javascript. Javascript has Array.map(), and jQuery has $.map(), but those only works on arrays, and I needed one that could do its magic on objects. So I wrote this one:
function mapObj(obj, fun) {
var ret = {};
for (i in obj) {
if (obj.hasOwnProperty(i)) {
fun.call({emit: function(key, value) {
ret[key] = value;
}}, i, obj[i]);
}
}
return ret;
}
mapObj() takes an object and a function, applies the function to each property of the object, gathers up the result and returns it as a new object. The function supplied to mapObj is called with two parameters, the key and value of the current property. To add properties to the final object, call this.emit(key, value) from the function. This may be called any number of times for each property (including zero).
Here’s a usage example:
var obj = {a:1, b:2, c:3, d:4};
var obj2 = mapObj(obj, function(key, val) {
if (val != 2) {
this.emit(key.toUpperCase(), val*2);
} else {
this.emit(key, val);
this.emit('aaa', 'bbb');
}
});
// {A:2, b:2, aaa:'bbb', C:6, D:8}
Maybe someone will find this useful.
First, chop an onion. And some garlic. Couple of cloves, I dunno.
Fry in some oil until tender. Toss in some meat. Like, half a kilo of minced meat or something. Keep frying until it’s, like, fried.
Add a couple of chopped tomatoes, and some salt and pepper. Can’t do without that shit. Then start adding head: Maybe a couple of red chili peppers, a habanero if you’re feeling feisty. Some dried chili, and a chipotle for that nice smoky flavour. Just like whatever you have on hand. Throw in some other spices as well, stuff like cumin, oregano, cilantro, paprika. Teaspoon of sugar, maybe some lemon juice. Maybe add some water and let it boil down to get everything together and tasty-like.
Cook a whole bunch of french fries. Preferably in a deep fryer, if you have one. I have one, it’s awesome. You should get one if you don’t have one. Throw them in a casserole, add some salt if you like. Pour on the meat-chili-stew-thing, add some jalapenos, and cover with a couple handfuls of grated cheese. Bake in the oven until the cheese is melted and golden and/or you’re desperately hungry.
Serve with sour cream, salsa and an antacid.
My name is Arne Martin Aurlien. I run this thing. Here’s a few facts about me:
Here’s a few things I have made: