June 26, 2014

DOM Insertion Test

While I worked on some task that includes inserting of many HTML elements into the document I was wandering what the fastest method is. I tried (basically) three methods:

The fastest method is the last and the slowest is the first method. But sometimes is better use safe DOM approach so in this cases is the best using of the second method.

Some advices

  1. Make HTML you are inserting as simple as is possible - each attribute counts!
  2. If you create many elements and want event handlers attached to them don`t do it for each one element but attach one event handler to the parent element and then inside the handler self determine what the target element is.
  3. Insert large amount of new elements in portions not in once. The advantage is that user always see that something is happening, the disadvantage is that it is little slower than do it at once.

Below is jsFiddle with the testing document (http://jsfiddle.net/ondrejd/kLw52/):

June 24, 2014

IDE hidden in Firefox nightly

Today I read interesting article on the Mozilla Hacks blog about new WebIDE and I have to say that on my low-cost netbook is this the first IDE targeted on mobile system that actually works and is usable on slower machines (including emulator of course).
Below is a screencast which I borrowed from the original article:

I must say that while Firefox maybe have not market-share as some time ago but still it is the perfect solution for the professionals.

June 23, 2014

TagsSidebar - new UI proposals

Currently I'm working on next version of TagsSidebar - besides I'm trying Mozilla Add-on SDK I also created new layout for the main view - here are the screenshots:

Default view

No details and no favicons

No details but with favicons

Full details but no favicons

Hopefully, you will like them :)

PS: While now I'm dealing with Add-on SDK I want to create blog post where I will compare add-on development using SDK and the old-school way - so stay tuned.

June 11, 2014

TagsSidebar 1.0

I just finished (and published on AMO) my new add-on TagsSidebar. It extends Mozilla Firefox with sidebar that allows easy and quick browsing your bookmarks by selecting tags that have attached.

Here are some important links:

And here goes few screenshots:

June 8, 2014

Creating sidebar add-on for the Firefox with Australis UI

I'm creating simple add-on for Mozilla Firefox and even I did such add-ons before I run into the troubles. It's because of new Firefox UI called Australis and because I want this add-on to be bootstrapped (so it doesn't require browser restart to complete the installation).
After a short googling I found CustomizableUI.jsm and I finally got the working solution.
So here is my bootstrap.js which adds the sidebar:

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const { classes: CC, interfaces: CI, utils: CU } = Components;
const self = {
    id: "tagssidebar@ondrejd.info",
    name: "TagsSidebar",
    path: {
        chrome: "chrome://tagssidebar/"
const prefPrefix = "extensions." + self.id + ".";


var gStylesSrv;
var gStylesURI;

// Bootstrap API: install(aData, aReason)
function install(aData, aReason) {
    if (aReason == ADDON_INSTALL) {
        // Set default preferences
        let prefs = Services.prefs.getBranch(prefPrefix);
        prefs.setBoolPref("showInSidebar", true);
        prefs.setBoolPref("showTagCloud", false);
        prefs.setBoolPref("showFavicons", false);
} // end install(aData, aReason)

// Bootstrap API: uninstall(aData, aReason)
function uninstall(aData, aReason) {
    if (aReason == ADDON_UNINSTALL) {
        // Remove default preferences
} // end uninstall(aData, aReason)

// Bootstrap API: startup(aData, aReason)
function startup(aData, aReason) {
    // Create new toolbar button
        id: "tagssidebar-toolbarbutton",
        defaultArea: CustomizableUI.AREA_NAVBAR,
        label: "TagsSidebar",
        tooltiptext: "Toggle visibility of TagsSidebar.",
        type: "button", 
        onBeforeCreated: function(aDocument) {
            // We need to add more UI than the toolbarbutton (broadcaster, key and menuitem):
            // Broadcaster
            let bcset = aDocument.getElementById("mainBroadcasterSet");
            if (bcset) {
                let bc = aDocument.createElementNS(XUL_NS, "broadcaster");
                bc.setAttribute("autoCheck", "false");
                bc.setAttribute("group", "sidebar");
                bc.setAttribute("id", "viewSidebar_tagssidebar");
                bc.setAttribute("oncommand", "toggleSidebar('viewSidebar_tagssidebar');");
                bc.setAttribute("sidebarurl", "chrome://tagssidebar/content/sidebar.xul");
                bc.setAttribute("sidebartitle", "TagsSidebar");
                bc.setAttribute("type", "checkbox");
            // Key
            let keyset = aDocument.getElementById("mainKeyset");
            if (keyset) {
                let key = aDocument.createElementNS(XUL_NS, "key");
                key.setAttribute("command", "viewSidebar_tagssidebar");
                key.setAttribute("id", "key_openSidebar_tagssidebar");
                key.setAttribute("key", "t");
                key.setAttribute("modifiers", "accel,shift");
            // Menuitem
            let mp = aDocument.getElementById("viewSidebarMenu");
            if (mp) {
                let mi = aDocument.createElementNS(XUL_NS, "menuitem");
                mi.setAttribute("key", "key_openSidebar_tagssidebar");
                mi.setAttribute("label", "TagsSidebar");
                mi.setAttribute("observes", "viewSidebar_tagssidebar");
                mi.setAttribute("tooltiptext", "Toggle visibility of TagsSidebar!");
        onCreated: function(aNode) {
            // Add ID of broadcaster we created before as a command:
            aNode.setAttribute("command", "viewSidebar_tagssidebar");
            return aNode;

    // Load stylesheet
    gStylesSrv = CC["@mozilla.org/content/style-sheet-service;1"].getService(CI.nsIStyleSheetService);
    gStylesURI = Services.io.newURI(self.path.chrome + "skin/overlay.css", null, null);
    gStylesSrv.loadAndRegisterSheet(gStylesURI, gStylesSrv.USER_SHEET); 
} // end startup(aData, aReason)

// Bootstrap API: shutdown(aData, aReason)
function shutdown(aData, aReason) {
    if (aReason == APP_SHUTDOWN) return;

    // Destroy our widget

    // Unload stylesheet
    if (gStylesSrv.sheetRegistered(gStylesURI, gStylesSrv.USER_SHEET)) {
        gStylesSrv.unregisterSheet(gStylesURI, gStylesSrv.USER_SHEET);
} // end shutdown(aData, aReason)