sciter-sdk / pysciter

Python bindings for Sciter
https://sciter.com
MIT License
396 stars 40 forks source link

How to call Javascript function from python? [question] #65

Closed PieceOfGood closed 2 years ago

PieceOfGood commented 2 years ago

The only example I found here. True, it is about the opposite, but in the question discussed there, there is just an example that should work for me sciter.Window().call_function('func_name') but it does not work. I tried to wrap it in a frame in the same way as you did in your example pysciter.py and then call from the instance context self.call_function('func_name') but it does not work too. Could you add to the minimal example a button that calls a function from a javascript to python, which calls a javascript function with an alert in window?

pravic commented 2 years ago

sciter.Window().call_function('func_name')

This creates a new empty window, calls a function, and destroys that window.

pravic commented 2 years ago

From Javascript to Python: use an event handler (frame is also an event handler) with @script in Python to implement such function. In JS call it with Window.this.xcall.

From Python: frame.call_function if you are outside of a handler or self.call_function in you're inside of it.

pravic commented 2 years ago

See pysciter.py and pysciter.htm in https://github.com/sciter-sdk/pysciter/tree/master/examples. It's for TIScript but the idea is the same. Also see minimal.htm, it contains both JS and TIS.

PieceOfGood commented 2 years ago

main.py file:

import os
import sciter

ROOT_DIR = os.path.abspath(".")
HTML_PATH = os.path.join(ROOT_DIR, "main.html")

class Frame(sciter.Window):
    def __init__(self):
        super().__init__(ismain=True, uni_theme=True)

    @sciter.script
    def ScriptCallTest(self):
        print("ScriptCallTest()")
        self.call_function("test")

if __name__ == '__main__':
    frame = Frame()
    frame.load_file(HTML_PATH)
    frame.expand()
    frame.run_app()

main.html file:

<html>
<head>
    <title>Title</title>
</head>
<body>
    <button id="test">Test</button>
</body>
<script type="module">
    const view = Window.this;

    document.$("#test").addEventListener("click", () => {
        view.xcall("ScriptCallTest");
        console.log("<--- call test --->");
    });

    function test() {
        console.log("---> test called <---");
        view.modal("Call Test!");
    }
</script>
</html>

Please correct if something is wrong in the example, but I do not understand what else is required of me to work as I expect. image

And when I start the pysciter.py from example — nothing happens. pysciter_example

PieceOfGood commented 2 years ago

I create a virtual machine on Windows 10 and ran this example there. Function test() from the page context is not called too. Windows 10 Python 3.9.9 image

pravic commented 2 years ago

It works in <script> but not in <script type="module">. See https://github.com/c-smile/sciter-js-sdk/blob/main/demos/integration/res/default.htm#L21 and https://github.com/c-smile/sciter-js-sdk/blob/main/demos/integration/res/default.htm#L130

@c-smile Andrew, is this expected?

c-smile commented 2 years ago

It works in <script> but not in <script type="module">.

Yes, that's by JS [modules] design.

Each module has its own namespace. Functions defined there appear in module context only.

Use explicit globalThis.xxx declaration like this:

globalThis.test = function test() {
   ...
}

when you need to place function in global context from modules.

PieceOfGood commented 2 years ago

Thank you very much!