tempalias.com – creating the bookmarklet
Now that the bookmarklet feature is finished, let me take a few minutes to reflect on its creation, in the spirit of continuing the development diary.
The reason for the long silence after the launch is, believe it or not, the weather: Over the time I made the initial tempalias service, I began to really enjoy taking my 17inch MacBook Pro outside on the balcony and write code from there. In fact, I enjoyed it so much that I really wanted to continue that tradition when doing more work on the site.
Unfortunately from May first until May 21st it was raining constantly which made coding on the balcony kind of no-fun to do.
Now the weather was great and I could finish what I began way earlier.
So. How does one create a bookmarklet?
I didn't know much either, but in the end, the essence of a bookmarklet is JavaScript code that gets executed in the context of the page you are on when you are executing it. So that's something to work with.
Of course, you don't want to add all the code you need for your magic to work into that link target - that would be unmaintainable and there's some risk of breakage once the link gets too big - who knows at what size of the script browsers begin cutting off the code.
So you basically do nothing but creating a script tag sourcing the real script. This is what I'm doing too - the non-minified version of that code is in util/bookmarklet_launcher_test.js.
Looking at that file, you'll notice that the bookmarklet itself is configurable using that c variable (keeping the names short to keep the code as short as possible). The configuration is done on the results page that is shown once the alias has been generated (public/templates/result.template).
Why the host name? Because the script that is injected (public/bookmarklet.js) doesn't know it - when it's sourced, window.location would still point to the site it was sourced on. The script is static code, so the server can't inject the correct host name either - in fact, all of tempalias is static code aside of that one RESTful endpoint (/aliases).
This is a blessing as it keeps the code clean and a curse as it makes stuff harder than usual at places - this time it's just the passing around of the host name (which I don't want to hard-code for easier deployment and development).
The next thing of note is how the heavy lifting script is doing its work: Because the DOM manipulation and event-hooking up needed to make this work is too hard for my patience, I decided that I wanted to use jQuery.
But the script is running in the context of the target site (where the form field should be filled out), so we neither can be sure that jQuery is available nor should we blindly load it.
So the script is really careful:
- if jQuery is available and of version 1.4.2, that one is used.
- If jQuery is available, but not of version 1.4.2, we load our own (well - the official one from Google's CDN) and use that, while restoring the old jQuery to the site.
- If jQuery is not available, we load our own, restoring window.$ if it pointed to something beforehand.
This procedure would never work if jQuery wasn't as careful as it is not to pollute the global namespace - juggling two values (window.$ and window.jQuery) is possible - anything more is breakage waiting to happen.
The last thing we need to take care of, finally, is the fact that the bookmarklet is now running in the context of the target site and, hence, cannot do AJAX requests to tempalias.com any more. This is what JSONp was invented for and I had to slightly modify the node backend to make JSONp work for the bookmarklet script (this would be commit 1a6e8c - not something I'm proud of - tempalias_http.js needs some modularization now).
All in all, this was an interesting experience between cross domain restrictions and trying to be a good citizen on the target page. Also I'm sure the new knowledge will be of use in the future for similar projects.
Unfortunately, the weather is getting bad again, so the next few features will, again, have to wait. Ideas for the future are:
- use tempalias.com as MX and CNAME as to create your own aliases for our own domain
- create an iphone / android client app for the REST API (/aliases)
- daemonize the main code on its own without the help of some shell magic
- maybe find a way to still hook some minimal dynamic content generation into paperboy.
tempalias.com – bookmarklet work
While the user experience on tempalias.com is already really streamlined, compared to other services that encode the expiration settings and sometimes even the target) into the email address (and are thus exploitable and in some cases requiring you to have an account with them), it loses in that, when you have to register on some site, you will have to open the tempalias.com website in its own window and then manually create the alias.
Wouldn't it be nice if this worked without having to visit the site?
This video is showing how I want this to work and how the bookmarklet branch on the github project page is already working:
The workflow will be that you create your first (and probably only) alias manually. In the confirmation screen, you will be presented with a bookmarklet that you can drag to your bookmark bar and that will generate more aliases like the one just generated. This works independently of cookies or user accounts, so it would even work across browsers if you are synchronizing bookmarks between machines.
The actual bookmarklet is just a very small stub that will contain all the configuration for alias creation (so the actual bookmarklet will be the minified version of this file here). The bookmarklet, when executed will add a script tag to the page that actually does the heavy lifting.
The script that's running in the video above tries really hard to be a good citizen as it's run in the context of a third party webpage beyond my control:
- it doesn't pollute the global namespace. It has to add one function, window.$__tempalias_com, so it doesn't reload all the script if you click the bookmark button multiple times.
- while it depends on jQuery (I'm not doing this in pure DOM), it tries really hard to be a good citizen:
- if jQuery 1.4.2 is already used on the site, it uses that.
- if any other jQuery version is installed, it loads 1.4.2 but restores window.jQuery to what it was before.
- if no jQuery is installed, it loads 1.4.2
- In all cases, it calls jQuery.noConflict if $ is bound to anything.
- All DOM manipulation uses really unique class names and event namespaces
While implementing, I noticed that you can't unbind live events with just their name, so $().die('.ta') didn't work an I had to provide all events I'm live-binding to. I'm using live here because the bubbling up delegation model works better in a case where there might be many matching elements on any particular page.
Now the next step will be to add some design to the whole thing and then it can go live.
All-time favourite tools – update
It has been more than four years since I've last talked about my all-time favourite tools. I guess it's time for an update.
Surprisingly, I still stand behind the tools listed there: My love for Exim is still un-changed (it just got bigger lately - but that's for another post). PostgreSQL is cooler than ever and powers PopScan day-in, day-out without flaws.
Finally, I'm still using InnoSetup for my Windows Setup programs, though that has lost a bit of importance in my daily work as we're shifting more and more to the web.
Still. There are two more tools I must add to the list:
- jQuery is a JavaScript helper libary that allows you to interact with the DOM of any webpage, hiding away browser incompatibilities. There are a couple of libraries out there which do the same thing, but only jQuery is such a pleasure to work with: It works flawlessly, provides one of the most beautiful APIs I've ever seen in any library and there are tons and tons of self-contained plug-ins out there that help you do whatever you would want to on a web page.
jQuery is an integral part of making web applications equivalent to their desktop counterparts in matters of user interface fluidity and interactivity.
All while being such a nice API that I'm actually looking forward to do the UI work - as opposed to the earlier days which can most accurately be described as UI sucks. - git is my version control system of choice. There are many of them out there in the world and I've tried the majority of them for one thing or another. But only git combines the awesome backwards-compatibility to what I've used before and what's still in use by my coworkers (SVN) with abilities to beautify commits, have feature branches, very high speed of execution and very easy sharing of patches.
No single day passes without me using git and running into a situation where I'm reminded of the incredible beauty that is git.
In four years, I've not seen one more other tool I've as consistenly used with as much joy as git and jQuery, so those two certainly have earned their spot in my heart.