HeinrichApfelmus / threepenny-gui

GUI framework that uses the web browser as a display.

Home Page:https://heinrichapfelmus.github.io/threepenny-gui/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Calling Haskell from JavaScript

bradrn opened this issue · comments

When using exportHandler to export a Haskell function to JavaScript, how do you call the exported function from the JavaScript side?

You can use it like an ordinary JavaScript function, e.g.

handler <- ffiExport something
runFunction $ ffi "%1('hello')" handler

I should probably write this down somewhere in the documentation.

I think you misinterpreted my question --- I should probably have been clearer. This is what I meant to ask:

Can you call a Haskell function from a JavaScript script e.g. something like this:

--Main.hs
...
    handler <- ffiExport something
...
// Script.hs
...
runHaskellFunction()
...

Perhaps confusingly, the ffiExport function does not add a new name to the JavaScript namespace. Instead, it turns a Haskell function into something that can be used on the JavaScript side.

The ffi function is the only way to transport this function to the JavaScript side. You can always do

handler <- ffiExport something
runFunction $ ffi "window.myFunction = %1" handler

to make a new identifier myFunction available in the global JavaScript namespace.

Thank you!


You can use it like an ordinary JavaScript function, e.g.

handler <- ffiExport something
runFunction $ ffi "%1('hello')" handler

I should probably write this down somewhere in the documentation.

It might also be a good idea to record the method you gave for 'exporting' a Haskell function in the documentation.


P.S.: In case you want to know what I needed this for, I'm using it to create a menu using Electron (see #111 and https://github.com/HeinrichApfelmus/threepenny-gui/blob/master/doc/electron.md). My code:

-- Main.hs

module Main where

import qualified Graphics.UI.Threepenny       as UI
import           Graphics.UI.Threepenny.Core

...

setup :: Window -> UI ()
setup window = do
    fname <- UI.input
    saveBtn <- UI.button # set text "Save file"
    box <- UI.textarea # set UI.id_ "text"
    ...
    let fun = void $ runUI window $ element box # set text "Hello from Haskell!"
    handler <- ffiExport fun
    runFunction $ ffi "window.sayHello = %1" handler
    ...
// electron.js
...

  function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({
      width: 800,
      height: 600,
      webPreferences: { nodeIntegration: false },
    });

    ...

  app.on('ready', () => {
    ...
    setMainMenu()
  });

  ...

  // based on http://stackoverflow.com/a/37798089
  function setMainMenu() {
    const template = [
      {
        label: 'Hello',
        submenu: [
         {
           ...
           label: 'Hello from Haskell',
           accelerator: 'CmdOrCtrl+H',
             click() {
                 win.webContents.executeJavaScript('window.sayHello()')
             }
         }]
      }
    ];
    Menu.setApplicationMenu(Menu.buildFromTemplate(template));
  }
});