Firefox extension is sending javascript Array as a

2019-05-16 16:25发布

I have problem passing JavaScript arrays to an Add-On, which I'm writing in Add-on Builder.

To communication I'm using events and sending an event with an array, but the Add-on (Content Script) gets an object, not an array.

This is event:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml"> 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
<script type="application/x-javascript">

$(function() {
    $(window).bind('Runner-PageEvent', function(event) {
        console.log('PAGE: Reakcja na Runner-PageEvent na stronie');
    });

    $(window).bind('RunnerResult', function(event) {
        console.log('PAGE: Result is ' + event.originalEvent.detail.Result);

//// PROBLEM!!!
        console.log('PAGE: Should be array: ' + event.originalEvent.detail.array); // firebug shows object

        });

    $(window).bind('Runner-DetectCallback', function(event) {
        console.log('PAGE: Reakcja na Runner-DetectCallback na stronie');
        $('#browser-detection').text('Extension detected').css('background-color', 'green').css('color', 'white');
    });

    var event = new CustomEvent("Runner-Detect", {});
    window.dispatchEvent(event);
    console.log('PAGE: Runner-Detect sent');
});

function CallExtension() {
    var event = new CustomEvent("Runner-PageEvent", { detail : {
            a: "messageA",
            b: "messageB",
            c: "messageC",
            d: "messageD",
            arrayA: ["a", "b", "c", "d"],
            arrayB: [0, "info", "info2", 3]
        }});
    window.dispatchEvent(event);
    console.log('PAGE: CALL EXTENSION clicked');
}

</script> 
</head>
<body>
<div id="browser-detection" style="background-color: red">No extension</div>
<br/>
Run extension: <button onclick="CallExtension()">Run!</button>
</body>
</html>

Firebug shows me event as object with one property detail.tab as array with four items.

Content script receives an object e, where e.detail.tab is an object (but should be an array).

window.addEventListener(
    'eventname', 
    function(e) { 
        // console.log(e.detail.tab.length); -> produce an error on console (Ctrl+Shift+J)
        // console.log(e.detail.tab[0]); -> as above
        for(var x in e.detail.tab){
            console.log(x);
            console.log(e.detail.tab[x]);
        }            
        self.port.emit('SendToExtension', e.detail);
    }
);


I don't know if there is a problem with Add-on Builder or I'm doing something wrong?
Please help!

1条回答
放我归山
2楼-- · 2019-05-16 17:23

There appears to be a bug in how CustomEvent() transmits information in and out of the sandbox (XPCNativeWrapper). It's improperly serializing the CustomEventInit.detail value in certain circumstances and, after the first such instance, fails to pass the detail value at all -- suggesting some kind of memory/state corruption is taking place.

  1. For the following, refer to this test page: jsbin.com/ajegib/1.

  2. Install, or run in "Test" mode, this Firefox add-on: CustomEvent data_ across the sandbox.

  3. Note that both the test web-page, and the extension's content script have code like this:

    window.addEventListener ("EventWithArrayData", function (zEvent) {
        console.log (
            "Event detail: ", zEvent.detail, Array.isArray (zEvent.detail)
        );
    } );
    
    var zEvent = new CustomEvent ("EventWithArrayData",
        {"detail": [5,6,7] }
    );
    window.dispatchEvent (zEvent)
    
  4. Open both Firebug's console, and the Firefox Error Console (CtrlShiftJ) to observe the results as custom events with array values for detail are sent. (You can press the Normal array data button, to send them.)


What should happen:

Both the web page and the extension should see the data, from both events, as an array.

  1. The Firebug console should display:

    **The Normal button was pressed.**
    In web page (Normal) from page: [1, 2, 3]  true
    In web page (Normal) to page: [5, 6, 7]  true
    
  2. The FF Error console should display:

    info: In Content Script (Normal) from page:  1,2,3 true
    info: In Content Script (Normal) to page:  5,6,7 true
    


What does happen:

  1. On the First Event:

    1. The Firebug console displays:

      **The Normal button was pressed.**
      In web page (Normal) from page: [1, 2, 3]  true
      In web page (Normal) to page: {0: 5, 1: 6, 2: 7}  false
      
    2. The FF Error console displays:

      info: In Content Script (Normal) from page:  [object Object] false
      info: In Content Script (Normal) to page:  5,6,7 true
      
  2. On the All subsequent Events:

    1. The Firebug console displays:

      **The Normal button was pressed.**
      In web page (Normal) from page: [1, 2, 3]  true
      In web page (Normal) to page: null  false
      
    2. The FF Error console displays:

      info: In Content Script (Normal) from page:  [object Object] false
      info: In Content Script (Normal) to page:  null false
      

Observe:

  1. In all cases, the web page sees the array data sent by its own event correctly. It sees an array.
  2. But, the extension sees an array-like object instead.
  3. Array data, sent from the extension, appears correctly to the extension on the first pass but is null on all subsequent attempts.
  4. Array data, sent from the extension, appears as an object to the page and then not at all (null)!


Workaround:

Both the CustomEvent documentation and the DOM Standard state that eventInitDict.detail can have any type. But for events sent across the add-on sandbox, this is clearly not the case.
There don't seem to be any Firefox bugs for this. Perhaps we should open one.

Anyway, the workaround that seems to work is to JSON encode the data we send with CustomEvent().

Send like so:

var detailVal   = JSON.stringify ( [1, 2, 3] );

var zEvent = new CustomEvent ("EventWithJSON_Data",
    {"detail": detailVal }
);
window.dispatchEvent (zEvent)

Receive like so:

window.addEventListener ("EventWithJSON_Data", function (zEvent) {
    var datArray    = JSON.parse (zEvent.detail);
    console.log (
        "JSON data: ", datArray, Array.isArray (datArray)
    );
} );


You can see this at work on the test page + extension by pressing the JSON-encoded array data button. (Be sure to refresh the page first to clear the corruption discussed above.)

查看更多
登录 后发表回答