Snippets code from my daily experience

June 29, 2008

Open a tab using FUEL on Firefox 3

Filed under: extension, firefox, fuel, mozilla, nsIIOService, xpcom, xul — dafi @ 5:41 pm

I want to migrate to Firefox 3 and stop compatibility with FF2.x so I’m starting to use intensively FUEL.

Today I’ve replaced the old “open new tab” code shown below

newTab : function (url) {
const newTab = getBrowser().addTab(url);
getBrowser().selectedTab = newTab;
}

With the FUEL version

newTab : function (url) {
var uri = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService)
.newURI(url, null, null);
Application.activeWindow.open(uri);
}

Onestly I found so complicated the FUEL approach.

Why I need to create an URI?

Why open doesn’t work with a simple string?

BTW FUEL is great

May 9, 2008

How to detect XUL trees scroll event

Filed under: DOMAttrModified, extension, nsITreeView, visualdiffer, xpcom, xul — dafi @ 7:17 pm
Tags: , ,

My extension VisualDiffer contains two nsITreeViews that must synchronize scrolling, when user scrolls one the other tree moves the selection to the corresponding row.

Apparently XUL trees don’t have any event handler to intercept scrolling operations so I run the risk to became crazy.

After days spent to find a solution (using google) without result I’ve tried to use the DOMAttrModified event and amazingly it worked.

First I add a listener to the tree (VisualDiffer adds listeners to left and right trees)

document.getElementById(“left-tree”).addEventListener(“DOMAttrModified”,
function(event) { gFolderDiffer.onLeftScroll(event);}, false);

The onScroll simply checks if event.attrName is “curpos” and if it’s true the tree has been scrolled by user

onLeftScroll : function(event) { if (event.attrName == “curpos”) {
rightTreeView.treebox.scrollToRow(leftTreeView.treebox.getFirstVisibleRow());
}
}

This solution works fine but maybe exists a better way…

December 23, 2007

How to detect the current active theme name on Firefox

Filed under: extension, firefox, gecko, nsIPrefBranch, skin, theme, xpcom — dafi @ 6:42 pm

Sometime obtaining informations about components isn’t so quick, you must iterate over RDF, XML or call many API.

Sometime is very simple like get a pref string… well this time I’m lucky ;-)

The pref general.skins.selectedSkin contains the current active theme name.

var currentThemeName = Components.classes['@mozilla.org/preferences-service;1']
.getService()
.QueryInterface(Components.interfaces.nsIPrefBranch)
.getCharPref(”general.skins.selectedSkin”);

August 18, 2007

Put in clipboard same content in multiple formats using XUL.

Filed under: clipboard, nsIClipboard, nsISupportsString, nsITransferable, xpcom, xul — dafi @ 1:09 pm

Copy plain text in clipboard can be obtained using code shown below.

Components.classes["@mozilla.org/widget/clipboardhelper;1"]
.getService(Components.interfaces.nsIClipboardHelper)
.copyString(“<font color=’#FF0000′>Hello world</font>”);

Using this approach you can easily copy HTML text but… it remains plain text!
So if you copy the string <font color=’#FF0000′>Hello world</font> inside OpenOffice Calc (or Microsoft Word) you don’t see the text “Hello world” in red but the plain HTML tag.

Copy data (not necessary text) using a specific format requires nsITransferable’s use.
You specify the mime type and if destination application (where you paste the data) is able to understand the format the correct result appears.

The code below insert real HTML data into clipboard and when you paste for example in OpenOffice you see the colored text.

var textHtml = "<font color='#FF0000'>Hello world</font>";
var xferable = Components.classes["@mozilla.org/widget/transferable;1"]
.createInstance(Components.interfaces.nsITransferable);

xferable.addDataFlavor("text/html");
var htmlstring = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);

htmlstring.data = textHtml;
xferable.setTransferData(”text/html”, htmlstring, textHtml.length * 2);

var clipboard = Components.classes["@mozilla.org/widget/clipboard;1"]
.getService(Components.interfaces.nsIClipboard);

clipboard.setData(xferable, null,
Components.interfaces.nsIClipboard.kGlobalClipboard);

Consider you want be able to choose if text must be pasted like HTML or plain text, for example because some application can’t handle stylished code.
Consider a plain text editor, it handles text not colorful HTML so you need the ability to paste based on destination application.
It’s easy! You only need to add a new flavor to the code shown above

var plainText = "Hello world in plain";
xferable.addDataFlavor(”text/unicode”);
var unicodestring = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
unicodestring.data = plainText;
xferable.setTransferData(”text/unicode”, unicodestring, plainText.length * 2);

Now text editors receive the string “Hello world in plain” without any formatting and rich editors receive a colored “Hello world”.
Rich editors like OpenOffice Calc or Writer allow user to choose how to paste using the “Paste special” function.
You can choose to paste the same data in different format or different data per different format.

Table2Clipboard uses two flavors, you can take a look at its source code here.

July 7, 2007

Short-circuits, innocent code and nsIDOMEvent targets

Filed under: firefox, flock, mozilla, xpcom, xul — dafi @ 6:08 pm

An user on AMI tells me that my bonsai RichFeedButton doesn’t work when installed together with another extension.

I install the offended extension and discover that RichFeedButton breaks this little jewel!

The solution was simple but the bug hunting was hard :-(

The problem was into an innocent function associated with a listener that simply checks the nsIDOMEvent’s target id and attrName as shown below
if (event.target.id == “xxx” && event.attrName == “yyy”) {
...
}


For some motivations the “event.target” expression breaks the other extension.

I suspect event.target at some event stage isn’t valid and generates internally some error corrupting (???) the full event queue or simply I’m a bad programmer :-(

The solution??

Simply swaps first equality test with second one

if (event.attrName == “yyy” && event.target.id == “xxx”) {
...
}


The javascript short-circuit evaluation ensures me event.target.id is parsed only if first condition is true. :-)

Every day I learn something about XUL and its implementation… ;-)

June 30, 2007

Flock is a bug!!!!

Filed under: firefox, flock, mozilla, xpcom — dafi @ 9:34 am

The browser flock is developed starting from Mozilla Gecko code but has many specific features.

Together with many cool features the flock team has added many bugs not present in original Gecko code!

The last I found involves the DOMAttrModified event listener.
The code below works on Firefox 1.5, 2.x and 3.x (thunks) but doesn’t work on flock!!!

onLoad : function() {

var feedButton = document.getElementById("feed-button");

if (feedButton) {

// add the listener for feedButton

document.addEventListener("DOMAttrModified", RichFeed.onAttrModified, false);

// triggers a modification only to test the listener

feedButton.setAttribute("feeds", "true");

// onAttrModified should receive the modification but this doesn't occur on Flock

var v = feedButton.getAttribute("feeds");

}

}

onAttrModified : function(event) {

if (event.target.id == "feed-button") {

// never called with Flock browser

}

}

So my decision is to stop the flock support on my bonzai extensions, I have no time to search workarounds to all flock bugs.

Who cares for my decision? Nobody I know :-(

March 18, 2007

XPCom: download multiple files and block the execution

Filed under: firefox, mozilla, nsIWebProgressListener, xpcom — dafi @ 9:09 am

The problem is simple: you want to download a bunch of http pages and save their content into separated files but you want to wait all downloads finish before to advance to the next line of code.

Using the nsIWebProgressListener this can be accomplished easily using the same progress listener that increments a counter at every download completed.

When the counter reaches the total urls to download a callback function is called.

You can take a look at my implementation (used into ViewSourceWith) here

Blog at WordPress.com.