No way to access selected content in a XUL editor element ?

For a Firefox extension I am currently developing I am writing code allowing local editing of documents  and I am using the XUL Editor element for this which provides kind of an easy way to implement a HTML ( or text ) editor in a browser extension. Kind of … Of course there are hurdles and the major one currently was how to retrieve the selection made in the editor.

Why is that needed ? Let’s explain with one simple example. XUL Editor makes it easy to manipulate content thru Midas and the Document.execCommand interface. To insert a link you basically invoke that command with the options shown below:

editor.contentDocument.execCommand("createlink", false, url);

Document.execCommand takes care of inserting the appropriate html tags correctly around the portion of text you have selected. In order to implement this in a senseful way of course you have to come up with some dialog first to ask the user for that url to use for the link:

So far, so good. Now imagine a user selects a text for which a link already had been inserted before. Of course you want your dialog entry field to contain that URL so that the user has the chance to change ( or delete ) it. This is where that feature to detect the user selection in the editor element is needed – and I can think of more use cases ( like e.g. manipulating the attributes of an inserted image ).

I was googling for some time without any luck. Either this is one of the best hidden features in XUL or there is bascially no way to do it. The best hint I found here in the Microsoft Developer Network about using document.selection.createRange(). They actually provide a demo of this code … which is not working and ends with the following error shown in the console: “TypeError: document.selection is undefined”.

So far, so bad. Looks like I had to come up with my own hack and use what I have. As I said the easy way to manipulate selected content in a XUL editor is thru contentDocument.execCommand. I decided to come up with a ‘marker’ tag to mark selected text first before I continue processing it. Thus for my method to handle links I first did this:

editor.contentDocument.execCommand("hiliteColor", false, "000000");

This bascially applies a black background to the selected text, HTML wise it generates the following tags around the selection:

<span style="background-color: rgb(0, 0, 0);">...</span>

Now with the help of some jQuery magic I can easily find the selected text within my document. The following code demonstrates how I fetch an exisiting URL from the HTML code if an “a” tag is found, by accessing the “href” attribute of that tag:

    spans = $(html).find("span");
    $(spans).each( function () {
        if ($(this).attr("style") == "background-color: rgb(0, 0, 0);" ) {
            if ($(this).find("a").length) {
                url = $(this).find("a").attr("href");
            }
        }
    });

Next I display my dialog for the user to enter / change the given URL and then use this simple code to create the link or remove it if the user has deleted it so that my dialog returns an empty url:

    if (url == "") {
        editor.contentDocument.execCommand("unlink", false, url);        
    } else {
        editor.contentDocument.execCommand("createlink", false, url);        
    }

All what remains to do later on is to remove that “marker” tag after I am done with my processing, which I accomplish thru a regular expression:

patt1 = new RegExp("<span style\=\"background\-color\: rgb.0, 0, 0.;\">(.*)</span>","g");  
editor.contentDocument.documentElement.innerHTML =
        editor.contentDocument.documentElement.innerHTML.replace(patt1,"$1");

Works ! As I said: it’s a hack. It will break of course if any user decides to use black background somewhere in his document. May be I should use another less likely color for my magic, like rgb(0,0,1).

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: