3

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.

Filipe Silva
  • 21,189
  • 5
  • 53
  • 68
AMarch
  • 153
  • 2
  • 14

2 Answers2

2

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.

Community
  • 1
  • 1
nmaier
  • 32,336
  • 5
  • 63
  • 78
  • 1
    Hi, thanks very much for your reply. My response is a bit belated because I wanted to do some more experimentation before following this up. First, with regards to the problem I was having where none of the text nodes in my test HTML file were being enumerated - I've discovered that my add-on is NOT executed when a document is accessed via File->Open File. – AMarch Aug 13 '13 at 02:43
  • I'm not sure if this is by design, but it seems an unlikely oversight. When I uploaded the test file to my host and accessed it from there, the text nodes were displayed as expected. – AMarch Aug 13 '13 at 02:47
  • Second, I've found that the reason the text values I was expecting to find on YouTube video pages were "jumbled together" is that the first instances of those values are stored inside of JSON responses within the DOM (from what I can tell). In addition, the visible occurrences of these text values were missing because of the "AJAX" nature of the page - my node enumeration was taking place before those values had been added to the page, so it was missing them. Now I watch for document changes and re-run the enumeration when a change is detected. – AMarch Aug 13 '13 at 02:52
  • I've had awful problems with my JQuery AJAX requests. This StackOverflow question gave me some hints (I might ask a new question about this): http://stackoverflow.com/questions/7973643/error-in-jsonp-call-only-from-firefox-extension There are a number of issues, and I'm not entirely happy with my solution. To begin with, I can't allow JQuery to handle the callback automatically for me because its reference to "window" is not the "real" window, and the callback fails. – AMarch Aug 13 '13 at 03:01
  • So I set my own callback by specifying jsonpCallback, and adding a unsafeWindow.callback = function(data){ } function to my document. That's fine except... I lose my reference to "this", which is the element I want to update in the web page. Further, I ALWAYS get an error, :success never fires, but :error ALWAYS fires. :complete fires, though. This is where it gets complicated. – AMarch Aug 13 '13 at 03:05
  • My custom callback passes a parameter "data" which INCLUDES the full server response - but an error is still raised. :error seems to wipe out this response, so I can't access it in :complete (which fires later). So what I do is, store the response "data" in my custom callback in a global variable, then access this in :complete - which also allows me to reference "this", the element on the page that I want to update with the details supplied by the remote server. It's very messy, it feels like there should be a better way. – AMarch Aug 13 '13 at 03:07
  • 1
    Incidentally, I can't "thank" you with points because I don't have enough "reputation", but I appreciate your reply – AMarch Aug 13 '13 at 03:09
  • OK, I think I've done that correctly now! I hope so anyway - all the best – AMarch Aug 13 '13 at 23:23
1

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.

serv-inc
  • 35,772
  • 9
  • 166
  • 188
  • 1
    Thank you - I still need to come back to this and finish that portion of my project, so this is very useful to know. – AMarch Sep 07 '15 at 23:22