MediaPlus - Firefox addon

The last two posts described MediaPlus as a Chrome and an Opera extension. To extend the browser matrix, MediaPlus is now ported to work as a Mozilla Firefox extension. As described in the previous post, the core functionality of MediaPlus is to interact and change the contents of the web page. The peripheral functionality like stopping the plugin, re-scanning the page, etc are invoked using the browser addon UI.
The MediaPlus add on for Firefox uses the new Jetpack way to write "no-restart" plugins. The concepts are very similar to writing extensions on Opera or Chrome -
  • A singleton background page that runs as a background process. For firefox, this is the lib/main.js CommonJS module.
  • Pop out icon and the corresponding pop out panel defined in the main.js file.
  • Content Scripts, also defined in the background page.
As expected of the browsers, there are also significant differences and this post talks about the interesting issues that were tackled to get the firefox extension working.
First, there is no direct way to inject script into webpages dynamically. Though the page_mod allows script injections into the web page, the page_mod cannot be changed to add more scripts later. Unfortnately, page_mods also do not share the execution context and hence, cannot communicate in a straightforward way. Hence, scripts are added to the webpage when the pop out are clicked using the tabs.activeTab.attach method by adding a script tag to the page. The source of this script is obtained using the data.url method, relative to the extension.
To communicate with these added scripts, the (ugly) unsafeWindow method is used. Since no "trusted" addon methods are leaked while using the unsafeWindow, the security concerns should be addressed.
The scripts added in this way are inserted into the page immediatly. This turns out to be a problem if the target webpage is still loading. Once the web page finishes loading, all the injected scripts are replaced with the new content. The icon needs to be clicked again to start the add on. Though the tabs.on(ready) method exists, this is only invoked once the page has completed loading. Hence, we would need logic to re-load the scripts again, when the onReady (DOMContentLoaded) event is fired. I could also not find a way to unbind this event and hence, this seems to be fired for every navigation on the web page; another ugly solution. The onready could remember the all the tabs for which it was fired, but that it just too much housekeeping for now. For now, you would have to click on "Start MediaPlus" again, after the page has loaded to activate it.
Though the message passing was not as simple as Chrome, it looked better than the way things are done in Opera, with custom events in addition to the message channel.

The source for Firefox extension is available here and you can download the addon from here. Follow this space for updates on MediaPlus as a bookmarklet or as an extension for browsers. If you have suggestions or have found bugs, you can contact me here for help.
I have also  made the statistics for the addon public and you could see the number of users, downloads, etc here.

MediaPlus - Opera Extension

The previous post discussed MediaPlus as a Google Chrome Extension. MediaPlus lets users mpdify and take control of media content on web pages. It lets uses move, resize and change media content on the web page; all these tasks are about changing content on a web page. The bookmarklet version of MediaPlus inserts a javascript file in a webpage and this script is responsible for displaying the charms on images or flash videos when the mouse is moved over them.
In addition to this core functionality, MediaPlus also has additional actions like stopping it, rescanning the page for dymanically adding content or simply turning off full screen. In case of the bookmarklet, these actions are initiated by clicking the bookmarklet again. In the case of an extension, these options can be available off an icon in the browser UI, outside the web page.
The Google Chrome extension does exactly this - the core functionality is handled by a content injected into the web page while the peripheral functions are displayed in a pop out panel as a part of the browser UI. Writing an extension using Opera is very similar to writing a Chrome extension. In short, the extenion has three basic parts
  • A singleton background page with scripts, included in index.html and the background.js referred in the index file.
  • Pop out button and corresponding popout.html, defined in the index.html
  • Content script in the includes directory that are injected into all web pages.

There are also two differences and here is how they are solved for the Opera extension. First, passing messages between the pop out and the content script is not simple and requires a background script to broker the connection the first time. This article explains how it is achieved.
The second issue is that external stylesheets scripts are not injected into the page using API calls, but by placing the script inside the includes folder. This unfortunately means that it is harder to inject dynamic scripts in a page. The first version injects scripts by referring to external URL, but this practice is frowned upon. The latest version does the following. The scripts can be injected by reading them using XHR using paths relative to the extension root and inserting them as textContent of script tags in the web page. Since the content scripts seem to have access to the global window object of the web page, they can communicate with the injected scripts. Note that Google Chrome separates the execution context of the web page and the content script.
To load images dynamically, they are added as img elements in the background page, drawn on a canvas, and the base64 data:url returned by the canvas.toDataURL is passed back to the content script. The content script sets the data:uri as the source of the image to be drawn. Background images referred using external stylesheets are still not loaded. External stylesheets (like jquery UI css) have to be changed to have data:uri before building the runtime.
The Opera extension is available for download here and source code is available here. To follow MediaPlus, check out this page.

MediaPlus as a Chrome Extension

I had written about MediaPlus, a bookmarklet that gives you more control over media contents like Flash videos, images, games, HTML5 movies, etc. in my previous posts. Though the bookmarklet was powerful, it has some shortcomings inherent to bookmarklets. Many people hide the bookmarks toolbar on their browser to get more browsing space. Additionally, though the concept of adding a bookmark is known, bookmarklets with their javascript: protocol and adding them to the toolbar is still not common. Finally, people also voiced a concern that clicking on the bookmarklet icon to perform multiple actions like toggling it, rescanning the page, etc was not intuitive.
MediaPlus only manipulates an the DOM of an existing webpage as a result of certain user actions. The MediaPlus chrome extension provides a better user interface for triggering these user actions. It adds an icon next to the URL bar that needs to be clicked to interact with the extension. The rest of the post is about the technical details of the implementation.

Extensions for chrome can inject content scripts in a running page that can interact and change the DOM. MediaPlus chooses not to inject these scripts for all pages, but does so only when the user first clicks the "Start MediaPlus" button. The scripts are loaded from the extension in a background page. Since the runtime provided to this script is isloated from the javascript environment of the page, scripts and the page can have their own versions of libraries like JQuery.
Once the script is loaded, all media elements (flash, canvas, image, video, iframe) have a class added to them. The mouseover event handler that is added as a part of injecting the script kicks in to display the possible actions on the media element. This is the exact same code path as for the bookmarklet.

The only deviation here is the way notifications are shown. Since chrome provides webkit notifications, these are used instead of manually using divs for the bookmarklets.

When the user makes a video full screen or darkens the background, they may want to undo the action. In case of the bookmarklet, the bookmarklet icon in the toolbar needs to be clicked. In the case of the extension, clicking the icon brings up a menu that lets the user restore the media element to the previous state.

Except for these changes, the code path is just like the bookmarklet. Infact, the bookmarklet and the extension share the same core codebase, as illustrated in the source repository.The only additional work is to pass message between the popup on clicking the icon and the content script injected in the page.
The extension is available on the Chrome Web Store and do give me feedback on how you find it. The support page is here, and you can report bugs here.
Watch out this page for more updates.