My Dream Way To Write A Firefox Extension

Advertisement:

POWERED by FUSION

The add-ons community for Firefox is one of the largest, most vibrant sources for innovation in the browser. If you want to affect people, to reach them and make a difference in their daily lives, the Firefox extension platform is hard to beat, with over a billion downloads of Firefox add-ons in total.

I want to be able to participate in that community, but I find it difficult.

You see, I’m a Web development and not a software developer in the traditional sense. Things like compilers, linkers, and build steps are scary. I prefer the Web and how it allows real-time feedback and instant gratification. I prefer its super-low barrier to entry. I do web development because that’s where it’s possible for me to translate my thoughts into reality.

The thing is, there are hundreds of thousands of developers just like me.

They represent an amazing and untapped wealth of innovation, of vision towards the future user experiences of the web. Imagine if any 8th grader who can write a web page could fundamentally enhance the browser, or just make the web a better place for his/her Mom.

In addition to formal explorations that explore light-weight browser customization—Personas and Ubiquity—we’re talking with add-on developers now, and soon the wider development community, to explore potential improvements to the Firefox Add-ons system. These improvements wouldn’t replace the current Add-on method — instead they would add another approach more easily grokked by web developers. As Add-ons Lead Nick Nguyen recently said, “Mozilla is about choice”.

This is a sketch of how I’d like to be able to write a Firefox extension.

It’s a URL

There’s no build-step for writing most web pages. You just write the code, point your browser at it, and it goes, whether it’s local or remote. To include separate files or 3rd party libraries you just point to their URL. It’s light-weight and robust.

If to install an extension was to just give my browser a URL, I could easily use an cloud-based editor like Bespin to take care of all my dev needs, from version control, to concept, to distribution.

For development I want instant gratification with a minimum of fuss. It’s how developing and subscribing to Ubiquity commands work. The same, if not more so, should be true for add-ons.

The Code

Concise, easy, and webby is the goal. These are just sketches, and we’d love feedback and alternative dreams.

Let’s dive into some examples.

Weather Badge in the Navigation Bar

This add-on puts a button in the navigation bar that displays the current weather forecast. When clicked, it opens a page to more a more detailed weather forecast.

file: weather.ext

<extension>
  <button id="weather" width="100px" height="100px"/>

  <script id="init">
    updateWeather(){
      Utils.xhr({
        url: "http://...",
        callback: function( data ){
          var weather = $("#weather");
          weather.img = data.img;
          weather.text = data.description;
        }
      });
    }

    $("#weather").click(function(){
      window.open( "http://..." );
    });

    Browser.Windows.onload(function(){
      Browser.UI.NavigationBar.add({
        id: "weather"
      });

      updateWeather();
      setInterval( updateWeather, 1000*60 );
    });
  </script>
</extension>

Clock in the Status Bar

Let’s take another example, this one split into two files. Say I wanted to add a digital clock to the status bar. This is how I want the extension to look:

file: init.js

Browser.Windows.onload( function(){
  Browser.UI.StatusBar.add({
    href: "status-clock.html";
  });
});

file: status-clock.html

<html>
<head>
  <style>
    body{ height: 10px; width: 20px; background: transparent; color: black;}
  </style>
</head>

<body>
  <div id="time"></div>
  <script>
    // Update the time every second.
    setInterval( function(){
      jQuery("#time").text( Date().split(" ")[4] );
    }, 10);
  </script>
</body>
</html>

Tab Recover

One more. Let’s augment the new tab screen to show links to recently closed tabs, as well as add a context menu item that let’s you open a recently closed tab.

file: closed-tabs.ext

<extension>
  <li id="menu-item">Open last closed tab</li>

  <script id="init">
    Browser.Windows.Tabs.onload(function( window ){
      if( window.location != "about:blank" ) return;

      /* Construct a list (li's) of recently closed tabs in HTML format. */
      var recentTabs = ...;
      $( "li", recentTabs).onclick(function()){
        window.open( this.url );
      });

      $(window.document.body).append( recentTabs );
    });

    Browser.onload(function(){
      Browser.UI.ContextMenu.add({
        id: "menu-item",
        onclick: function(){
          /* Get the last closed tab. */
          var lastClosedTab = ...
          window.open( lastClosedTab.url );
        }
      });
    });
  </script>

</extension>

Debugging

I’d like to be able to open my extensions in a web page and debug them with Firebug. In the second example, because much of the code is outsourced to a HTML page, debugging it is as simple as pointing a browser at it.

For more complicated extensions, we can mock-out the Browser object so that the extensions can be prototyped in content-space.

Really, anything that gives line numbers and useful error messages would be a big help in debugging my mistakes.

Portable

Because everything is encapsulated in an API, the host user-agent gets to decide what extension points look and feel like. For instance, calling Browser.StatusBar.add() can do the correct (and different) thing on Firefox Mobile, Thunderbird, or Firefox proper.

Unit Tests

We need it, but I’m not sure what it should look like. Being “webby” means mixing business logic with display logic, which mixes unit tests with functional test. I’m not sure how to unravel the problem. Help!

Your Turn

These are my sketches and thoughts on how I’d like to be able to extend Firefox using my web-developer skill set. How would you like to be able to extend Firefox? What should the code look like? Let us know.

Blog posts with example code get extra brownie points — possibly in the form of the extra Firefox shirts sitting on my desk :)