8
votes

I'm trying to implement my very first Firefox add-on so I'm a completely beginner.

I've been reading about [page-mod][1] documentation on Firefox webpage. I still don't understand yet how to do it.

Basically in a basic html page I have a button, what I want is the following:

If I click the button, the button calls the Javascript Function runBash() (declared inside the html page) and this function can communicate with index.js (add-on script). It seems simple, but it's driving me crazy.

[UPDATED CODE]

index.js / main.js add-on code:

var { ToggleButton } = require('sdk/ui/button/toggle');
  var panels = require("sdk/panel");
  var self = require("sdk/self");
  var data = require("sdk/self").data;
  var pageMod = require("sdk/page-mod");

  pageMod.PageMod({
    include: data.url("./bash.html"),
    contentScriptFile: data.url("./content-script.js"),
    contentScriptWhen: "ready", // script will fire when the event DOMContentLoaded is fired, so you don't have to listen for this
    attachTo: ["existing", "top"],
    onAttach: function(worker) {
      worker.port.on("bash", function() {
        //var bash = child_process.spawn('/bin/sh', ['/root/tfg/data/test.sh']);
        alert("IT WORKS!");
      });
    }
  });


  var button = ToggleButton({
    id: "my-button",
    label: "UPF",
    icon: {
      "16": "./favicon-16.ico",
      "32": "./favicon-32.ico",
      "64": "./favicon-64.ico"
    },
    onChange: handleChange
  });

  var panel = panels.Panel({
    contentURL: self.data.url("./panel.html"),
    onHide: handleHide
  });

  var lynisAlreadyExecuted = false;
  function handleChange(state) {

      if (lynisAlreadyExecuted == false) {
        var child_process = require("sdk/system/child_process");

        var ls = child_process.spawn('/usr/sbin/lynis', ['-c', '-q']);

        ls.stdout.on('data', function (data) {
          console.log('stdout: ' + data);
        });

        ls.stderr.on('data', function (data) {
          console.log('stderr: ' + data);
        });

        ls.on('close', function (code) {
          console.log('child process exited with code ' + code);
        });
        lynisAlreadyExecuted = true;
      }

    if (state.checked) {
      panel.show({
        position: button
      });
    }
  }

  function handleHide() {
    button.state('window', {checked: false});
  }

  function enableButton2() {
    var information = String(navigator.userAgent);
    var checkOS = information.includes("Linux",0);
    var checkBrowser = information.includes("Firefox",0);
    if(checkOS && checkBrowser){
      alert("Your system meets the minimum requirements! :)");
      document.getElementById("button2").disabled = false;
    }
    else{
      alert("Your System is not compatible");
    }         
  }

content-script.js:

function runBash() {
    // rest of your code
    self.port.emit("bash");
}

bash.html:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="../css/layout.css" type="text/css" media="screen">
<link rel="stylesheet" href="../css/menu.css" type="text/css" media="screen">

</head>
<body>
    <script src="content-script.js"></script>

    <input type="button" value="CallBash" onclick="runBash();">

</body>
</html>
1
Please do not add errors as screenshots. Copy the text and include it either in a quote block. If it does not format well in a quote block, use a code block for the text. Having errors be included as screenshots makes the question much less useful. There is no way to copy, or have a search find, the error text. - Makyen♦

1 Answers

4
votes

So you are mixing up your main JS file, which is basically your background page for the extension, and the content script, which will be the injected JS. In your package.json file, you specify the main:

{
  "name": "my-addon",
  "title": "My Addon",
  "id": "12345678",
  "description": "Does cool things.",
  "author": "me",
  "version": "1.0",
  "main": "main.js", <--- this is your main
  "permissions": {"private-browsing": true}
}

In main.js, you are allowed to use require, and other SDK functionality. For your pageMod, you need to specify a separate JS file (the content script) which will be injected into the HTML of the target of the pageMod:

EDIT: Do not include the the content script with a <script> tag in your HTML, it is inserted by pageMod:

<body>
    <!-- <script src="content-script.js"></script> don't put this here --> 

    <input type="button" value="CallBash" onclick="runBash();">

</body>

Also, just as an alternative, I use worker.on (main.js) and self.postMessage (content-script.js) for this. Example:

pageMod.PageMod({
    include: data.url('bash.html'),
    contentScriptFile: data.url("content-script.js"), //<-- this is the content script
    contentScriptWhen: "ready",
    attachTo: ["existing", "top"],
    onAttach: function (worker) {
        worker.on("message", function(data) {
            if (data['action'] == 'bash') {
                worker.postMessage({'action':'did_bash'});
            }
        }
    }
});

Then in content-script.js:

function runBash() {
    self.postMessage({'action':'bash'});
}

self.on('message', function (reply) {
    if (reply['action'] == 'did_bash') {
        console.log('It works!');
    }
}