3
votes

I'm trying to get to grips with the Firefox addon SDK (previously known as Jetpack from what I understand), but I'm having problems working with the DOM.

I need to iterate over all of the text nodes in the DOM when a web page loads and make changes to some of the strings that they contain. I've posted a simplified version of what I'm doing below (new to Javascript, so forgive me any oddities).

    // test.js

    function parseElement(Element)
    {
      if (Element == null)
        return;

      var i = 0;
      var Result = false;

      if (Element.hasChildNodes)
      {
        var children = Element.childNodes;
        while (i <= children.length - 1)
        {
          var child = children.item(i);
          parseElement(child);
          i++;
        }
      }

      if (Element.nodeType == 3)
      {
        // For testing - see what the text node contains
        alert(Element.nodeValue);
        Result = true;
      }

      return Result;
    }

    window.addEventListener("load", function load(event)
    {
      window.removeEventListener("load", load, false);
      parseElement(document.body); 
    }

When I create a basic HTML document:

    <!-- test.html -->

    <html>
      <head>
        <script type="text/javascript" src="test.js"></script>
      </head>
      <body>
        <b>hello world</b>
        <p>foo</p>
        <i>test</i>
      </body>
    </html>

...include this Javascript file in the HEAD section then open it in Firefox, the "alert" displays 6 dialog boxes containing:

    1) "hello world"
    2) blank -> no visible characters, just a newline
    3) "foo"
    4) blank -> no visible characters, just a newline
    5) "test"
    6) blank -> no visible characters, just a newline

Exactly what I would expect to see.

The problem arises when I create an addon and use test.js as a page-mod Content Script from my main.js file (modified to remove the "addEventListener" part). When I use "cfx run" to start Firefox with my addon installed, then open the same HTML document (with the "script" part for the test.js file commented), the alerts do not display at all.

So that's the first puzzle. But having also navigated to other web pages - for example, a YouTube video page - the alert DOES display several dialogs, but they include very strange strings, mostly the content of script tags:

EDIT I don't have enough reputation to embed an image, so here's a link instead showing the sort of thing I mean instead: http://img46.imageshack.us/img46/5994/mtpd.jpg

And again, the text I would expect to see is absent.

Apologies for some of the redundancy below, but just to be clear: this is my main.js:

    main.js

    var data = require("sdk/self").data;
    var data = require("sdk/self").data;

    exports.main = function()
    {
      pageMod.PageMod({
        include: "*",
        contentScriptFile: [data.url("test.js")]
      });
    }

And the modified version of the Javascript file is identical to the "test.js" listing above, but for the end part:

    test.js

    <snip>
      ...
      return Result;
    }

    parseElement(document.body);

I've included my project files (if I can call them that) in a zip if it makes things easier to visualise: http://www.mediafire.com/?774iprbngtlgkcp

I've tried changing

    parseElement(document.body);

to

    parseElement(unsafeWindow.document.body);

in case it makes any difference, but the outcome is identical.

So I'm very puzzled about what's happening. I can't understand why the test.js file isn't picking out the text nodes (and only the text nodes) from the DOM when I use it as part of an addon, but does exactly what I would anticipate when included as a script in a HTML document. Can anyone shed any light on this?

Thank you in advance.

2

2 Answers

2
votes

Errors in your lib code and contentScripts are usually logged to the Error Console. Check what is printed there. Also see the SDK console module.

Your page-mod won't run because by default page-mods will run only after the load event. See the contentScriptWhen documentation.

script tags actually often have a text-node child containing the inline script source. So it is absolutely normal that those are enumerated as well.

For some discussion about walking tree nodes, see: getElementsByTagName() equivalent for textNodes However, if you're after the text of specific ids/classes, consider using document.querySelector/.querySelectorAll, or if you're after nodes that have a specific XPath, use document.evaluate. This very likely will be a lot faster.

Other than that, I cannot really tell what exactly your remaining issues are and what you're trying to achieve in the first place exactly, so I cannot advice on that.

1
votes

You wondered that

I've discovered that my add-on is NOT executed when a document is accessed via File->Open File.

That is by design. At match-pattern, it says that

A single asterisk matches any URL with an http, https, or ftp scheme. For other schemes like file, resource, or data, use a scheme followed by an asterisk, as below.

You can use the regular expression /.*/ to match all sites and all schemas.