8

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>
Cheknov
  • 1,892
  • 6
  • 28
  • 55
  • 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 Apr 29 '16 at 04:41

1 Answers1

4

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!');
    }
}
  • Yes, my main is: `"main": "index.js"`. Then...what's wrong in my code? I already added PageMod in `index.js`, what should I put on `content-script.js` ? I just want to execute this: `function runBash() { self.port.emit("bash"); }` when I click the button...simple as that but I can't see how... – Cheknov Apr 28 '16 at 22:23
  • @Gera you will have to move what you have in the script tag on your HTML site to a "privileged" content script (content-script.js for example), since normal page scripts cannot access the self.port API. You will also have to attach the listener from within the content script, since the page will not be able to see the content script (and thus doesn't get the definition of the runBash function). – humanoid Apr 28 '16 at 22:28
  • @humanoid But how can I do that? Can you help me with my code? I was searching on internet and I can't find examples, I'm a little bit lost with firefox sdk documentation. – Cheknov Apr 28 '16 at 22:33
  • @Gera What exactly are you confused on how to do?Adding an event listener? – humanoid Apr 29 '16 at 10:45
  • @humanoid For example, yes. I tried to follow the examples from firefox sdk doc but it's not working.... – Cheknov Apr 29 '16 at 11:41
  • @Gera post your updated code and error messages and I'll update my answer for you. I have no idea what you have done since my answer –  Apr 29 '16 at 11:43
  • @chrisd1100 Thank you so much, the code is updated now in the main post. Now i'm just trying to test displaying in the terminal: `console.log("IT WORKS!");` when I press the button on `bash.html` but it's not working... – Cheknov Apr 29 '16 at 12:31
  • @Gera I do not think an `alert` will work in `main.js`, use `console.log` instead to see if you are getting the message, also see updated answer. –  Apr 29 '16 at 12:40
  • @chrisd1100 I tried with your suggestions, not working...I can't see what's wrong... Your alternative is just for sending messages right? In real life i need to execute bash script so `console.log...` is only for testing purpose – Cheknov Apr 29 '16 at 12:53
  • @chrisd1100 @Gera as I mentioned ealier you would have to add the event listener within the content script too. So `document.querySelector('input[value="CallBash"]').addEventListener("click", runBash, false);` – humanoid Apr 29 '16 at 13:40
  • @chrisd1100 Can you edit your answer with this code? I assume you are using jQuery...I don't have any experience with jQuery...just JavaScript – Cheknov Apr 29 '16 at 17:18
  • @humanoid I've been trying with your jQuery code and still not working...can you help me please? – Cheknov May 02 '16 at 21:43
  • @Gera there is no jQuery in my answer nor chrisd1100's. Also "not working" is a very unprecise description of your issue and unlikely to get help. – humanoid May 03 '16 at 09:00
  • @humanoid Yes it's true, sorry for my mistake. Basically I added your code to my existing code but nothing changed... I'll edit later with your event listener. – Cheknov May 03 '16 at 09:45
  • @chrisd1100 I tried your alternative but i'm getting the following error launching the extension: `JPM [error] Message: SyntaxError: missing ) after argument list Stack: @resource://tfg/index.js:18:undefined` – Cheknov May 22 '16 at 17:54