B.

Custom Browser Extensions for Front End Developers

Booking.com is displayed in dozens languages all over the world. We also support over fifty currencies. You can browse prices on our site in either the accommodation's preferred currency or a currency of your choice. While we try our best to guess your preferred language and currency based on factors like the browser's language and IP address, it's impossible to always get it right. So we allow users to pick any language/currency combination. It's quite possible that a user could be browsing the site in Japanese while using Indonesian Rupiah. The number of such users will probably be a small percentage of our traffic, but at our scale, small percentages are often big numbers.

For a designer or developer trying to get a feature right that's an enormous test matrix to consider.

Enter SilverHammer

Instead of testing every single language/currency combination, we identified a handful of languages and currencies that have often proven to be a challenge for our features. If your feature doesn't break under this group, you can be reasonably sure that it'll handle other language/currency combinations well. To allow designers and developers to quickly check their features and A/B experiments with these languages and currencies, we built a Chrome extension internally known as SilverHammer.

SilverHammer - our internal Chrome extension

Under the hood

At one of our hackathons, it occurred to us that the idea of an extension for internal testing might be useful outside Booking.com. So we started putting together a boiler-plate extension which could be extended by others. The Switcher Chrome extension is the result. It allows you to add multiple development, staging, production URLs and switch between them using keyboard shortcuts or a small popup menu next to the URL in the Chrome address bar. You can have any number of development, staging, production groups and you are also not restricted to just three URLs.

Switcher configured

Switcher's page action

The extension has four main components:

Options page:

This is where you configure the extension. Since this is just a plain HTML page, you can also use third-party javascript libraries. For example, for Switcher, we use AngularJS, which supports templating and two-way data binding. This means you don't have to write a lot of tedious code to wire data between DOM and your internal data structures.

When you load the options page for the first time, you get a simple UI:

Switcher's option page

The UI is bound to the following data:

groups = [{
    'params': false,
    'websites' : [
        {
            'shortcut':'',
            'url':'',
        },
        { 
            'shortcut':'',
            'url':'',
        },
        {
            'shortcut':'',
            'url':'',
        }
    ]
}];

When you click the Add Group button, a new element is added to the groups[] array. Similarly, when you click the Add Item button, a new element gets added to the websites array under the respective groups element. Clicking the Save button stringifies groups[] to a JSON string and puts it into the Local Storage. It also generates a couple of supporting data structures to make the retrieval of a group corresponding to the user's current URL easy.

The params flag controls if the querystring parameters should be passed between the URLs in a group. For a typical set up that includes a development, staging, and production environment, this should be true.

Background page:

This page subscribes to the new tab notification and checks to see if the current URL is in one of the groups of URLs configured by the user. If it is, then it enables the Page Action icon in the address bar that allows users to switch between sites in a group. This page also loads the user settings from Local Storage and allows other components of the extension to query the settings rather than each component loading its own copy.

Page action:

This is the main UI that the users interact with. It queries the background page for the settings and builds a simple UI with a list of links to the URLs in a group. One caveat: links don't work inside a page action. You need to handle the clicks and explicitly open them.

window.onclick = function(event) {
    if(event.target.nodeName == 'A') {
        if(event.target.href) {
            if(tabId) {
                chrome.tabs.update(tabId, {"url": event.target.href});
                window.close();
            }
        }
    }
}

Content script:

Content scripts allow you to inject code into the current page, manipulate its DOM and so on. Think of it as Greasemonkey specific to your extension. For example, SilverHammer injects links to our internal accommodation editing tools when you are visiting a particular accomodation page (you can configure whether it should do so from the options page). The content script in Switcher (switcher.js) registers a handler for the keypress event. It checks if a keystroke corresponds to a URL in a group and switches to it.

Limitations

Right now the extension allows you to either carry the URL parameters between websites or carry nothing.

The extension also doesn't support adding a port or username@password to the URL.

The future

Eventually, we'd like to explore the ability to switch the user agent when switching sites, or, cycling through user agents for the same site. This is a frontend development workflow which is becoming increasingly common. And while there are extensions that do a great job of switching just the user agent, we think there is some value in unifying it with the URL switching in addition to the development, staging, production switching workflow.

We hope you'll find this extension a useful starting point for your projects.

Get the code

You can find the code for the Switcher extension discussed in this article on GitHub.

[edit 2014-01-31]: Some small edits to better clarify the option page and the problems we were solving

comments powered by Disqus