0 votes

Hello,

I am writing a multi-OS 3D Visualization Tool in Godot. Essentially, I am loading an XML-File from FileSystem, parsing it, and 3D-Visualizing relations in it.

This works great on Windows and Linux. I'd also have this running in Browser as HTML5 export. However, the FileSystem-access there is limited to a sandbox, i.e. the user cannot access his XML-files he wants to visualize.

I have found a related issue where the JavaScript-Singleton was extended by some easy download-feature. Is it possible to have something like that for "upload" so the user can upload (text-based) files from his FileSystem?

Edit: I also tried approaches like calling the JS FS-Read as one-liner, unfortunately that does not seem to work:

var textcontent = JavaScript.eval("const fs = require('fs');const buffer = fs.readFileSync('file:///C:/Work/infile.txt'); buffer.toString();")

Any help is appreciated! Thanks!

Godot version Godot_v3.4.4-stable_win64
in Engine by (19 points)

1 Answer

+1 vote
Best answer

Check out this which allows the user to upload images. Presumably you can alter the "accept" attribute to only allow xml files?

by (7,769 points)
selected by

@exuin : Thank you very much, that actually solved my problem.

I had to make following changes:

  • add my file-type (e.g. ".xml" as accepted file type in HTML5FileExchange.gd =
  • make the JavaScript reader read the file as text using readAsText() instead of readAsArrayBuffer()
  • emit the content of file being read instead of doing some image conversion (unfortunately, I did not find a way to distinguish different file types for now, somehow no filetype is being returned as of now)

I only need the upload-functionality, so I removed the download function. My scripts now look like this:

res://addons/HTML5FileExchange/HTML5FileExchange.gd

extends Node

signal read_completed
signal load_completed(file)

var js_callback = JavaScript.create_callback(self, "load_handler");
var js_interface;

func _ready():
    if OS.get_name() == "HTML5" and OS.has_feature('JavaScript'):
        _define_js()
        js_interface = JavaScript.get_interface("_HTML5FileExchange");

func _define_js()->void:
    #Define JS script
    JavaScript.eval("""
    var _HTML5FileExchange = {};
    _HTML5FileExchange.upload = function(gd_callback) {
        canceled = true;
        var input = document.createElement('INPUT'); 
        input.setAttribute("type", "file");
        input.setAttribute("accept", ".xodr");
        input.click();
        input.addEventListener('change', event => {
            if (event.target.files.length > 0){
                canceled = false;}
            var file = event.target.files[0];
            var reader = new FileReader();
            this.fileType = file.type;
            // var fileName = file.name;
            reader.readAsText(file);
            reader.onloadend = (evt) => { // Since here's it's arrow function, "this" still refers to _HTML5FileExchange
                if (evt.target.readyState == FileReader.DONE) {
                    this.result = evt.target.result;
                    gd_callback(); // It's hard to retrieve value from callback argument, so it's just for notification
                }
            }
          });
    }
    """, true)

func load_handler(_args):
    emit_signal("read_completed")

func load_file():
    if OS.get_name() != "HTML5" or !OS.has_feature('JavaScript'):
        return

    js_interface.upload(js_callback);

    yield(self, "read_completed")

    var fileType = js_interface.fileType;
    var fileContent = JavaScript.eval("_HTML5FileExchange.result", true) # interface doesn't work as expected for some reason

    emit_signal("load_completed", fileContent)

and the GDScript uses it like this:

func _on_UploadButton_pressed():
    HTML5File.load_file()

    var content = yield(HTML5File, "load_completed")

    get_node("/root/Control/RichTextLabel").text = content
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.