3

As said in the subject, I need to fill a web form using data locally available as excel tables. I am already making that with a combination of python and autohotkey, but I want to have some level of JavaScript control in order to correctly handle loading times and conditionals. As a web development newbie, I first thought I could just have a local iframe controlling the website where the form is, but I discovered soon enough that XSS thing that does not allow such a hack. I do not have access to the server.

The last iteration of my experiences is with Firefox webextensions, with which I hoped to open a local file (through a html5 file input widget), where I would previously have written my js code to fill the form. But apparently there are also limitations here, and I cannot make any sense out the docs I am looking at. My code is currently like that:

popup.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
  </head>
  <body>
    <input type="file" id="liquida-file" name="liquida">
    <br>
    <script src="background-script.js"></script>
  </body>
</html>

background-script.js

function handleFiles() {
    var fileList = this.files; /* now you can work with the file list */
    var myFile = fileList[0]
    var reader = new FileReader();

    reader.onloadend = function(evt){
    if (evt.target.readyState == FileReader.DONE) { // DONE == 2
            var filedata = evt.target.result;
        console.error("Analyzing file data")
        console.error(filedata)
        var data = JSON.parse(filedata)
        console.error(data)
    }
    };
    reader.readAsText(myFile)
}
var inputElement = document.getElementById("liquida-file");
inputElement.addEventListener("change", handleFiles, false);

This works as a standalone file, but not as the popup.html file of my webextension. In this case, none of the console.error lines are ever reached. BTW, here is my manifest.json:

manifest.json

{

    "manifest_version": 2,
    "name": "My extension",
    "version": "1.0",

    "description": "Retrieve local data.",
    "homepage_url": "http://Nonefornow",
    "icons": {
        "48": "icons/beautiful-icon.png"
    },

    "permissions": [
        "activeTab"
    ],

    "browser_action": {
        "browser_style": true,
        "default_icon": "icons/icon.png",
        "default_title": "My Ext",
        "default_popup": "popup.html"
    }

}

Is there any easier way to do what I am doing? I was expecting for this sort of thing to be a common need, am I wrong? And why doesn't my code work?

beaver
  • 523
  • 1
  • 9
  • 20
Tiago
  • 212
  • 4
  • 16

2 Answers2

2

This problem has been pointed out in this question: Firefox WebExtensions, get local files content by path. The solution given there is the following:

function readFile(_path, _cb){

    fetch(_path, {mode:'same-origin'})   // <-- important

    .then(function(_res) {
        return _res.blob();
    })

    .then(function(_blob) {
        var reader = new FileReader();

        reader.addEventListener("loadend", function() {
            _cb(this.result);
        });

        reader.readAsText(_blob); 
    });
};

but in this solution the absolute path has to be passed to the function, like here:

readFile('file:///home/saba/desktop/test.txt', function(_res){
    console.log(_res); // <--  result (file content)
});

If you want to load a file from an <input> field you have to pass the path of the file too, because for security reasons you can't retrieve that from the <input> field. My solution was to read the path from an input text field, reducing significantly the usability

html

path: <input type="input" id="importFilePathInput" value="file://" />
<br />
file: <input type="file" id="importFileInput" />

javascript

function importFromfile(){
  let filename = jQuery('#importFileInput').val().replace('C:\\fakepath\\', '');
  if (!filename) {
    console.log('Select a filename');
  } else {
    let path = jQuery('#importFilePathInput').val() + '/' + filename;
    if (!path.startsWith('file://')) {
      path = 'file://' + path;
    }
    fetch(path, {mode:'same-origin'})
      .then(function(result){
        return result.blob();
      })
      .then(function(blob){
        let reader = new FileReader();
        reader.addEventListener('loadend', function(){
          Model.save(JSON.parse(this.result)); // your function here
        });
        reader.readAsText(blob);
      });
  }
}

Note that unfortunately this solution doesn't work anymore on Firefox 57, giving the error:

TypeError: NetworkError when attempting to fetch resource.
beaver
  • 523
  • 1
  • 9
  • 20
-3

This works as a standalone file, but not as the popup.html file of my webextension.

Aha. I would check the permissions ...

Éric Viala
  • 596
  • 2
  • 12