• Stars
    star
    120
  • Rank 285,251 (Top 6 %)
  • Language
    Haskell
  • License
    BSD 3-Clause "New...
  • Created almost 6 years ago
  • Updated almost 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐ŸŒ A Haskell binding to the webview library created by Serge Zaitsev.

webviewhs logo

What is webviewhs?

webviewhs is a Haskell binding to the webview library created by Serge Zaitsev.

According to webview:

[webview is] a tiny cross-platform webview library for C/C++/Golang to build modern cross-platform GUIs. It uses Cocoa/WebKit on macOS, gtk-webkit2 on Linux and MSHTML (IE10/11) on Windows.

For more information, see the webview README.

webviewhs allows you to create native desktop windows and dialogsโ€”while at the same timeโ€”rich web-based UI experiences all wrapped up in the powerful, type-safe embrace of Haskell.

Coupled with PureScript for the front-end portion, you now have an end-to-end purely functional programming language solution for creating desktop apps.

Be sure to explore the provided examples.

How complete is the binding?

  • webview
  • webview_init
  • webview_loop
  • webview_eval
  • webview_inject_css
  • webview_set_title
  • webview_set_fullscreen
  • webview_set_color
  • webview_dialog
  • webview_dispatch
  • webview_terminate
  • webview_exit
  • webview_debug
  • webview_print_log

How do I install webviewhs?

In your my-project.cabal file, list webviewhs under build-depends: like so:

  build-depends:
      base >= 4.7 && < 5
    , webviewhs

If you're using stack >= 1.7.1, put the following in your stack.yaml:

extra-deps:
  - github: lettier/webviewhs
    commit: # Insert commit SHA1 here.

For older stack versions, put the following:

extra-deps:
  - git: https://github.com/lettier/webviewhs.git
    commit: # Insert commit SHA1 here.

And now the run the following.

stack install --only-dependencies

If you're using cabal, run the following:

git clone https://github.com/lettier/webviewhs.git
cd my-project
cabal sandbox init
cabal sandbox add-source ../webviewhs
cabal --require-sandbox install --only-dependencies

Depending on your cabal version, you may be able to specify the git repository and commit much like stack.

How do I use webviewhs?

If you want to open up a native desktop window that loads a web page and manages itself, do the following:

{-# LANGUAGE
    OverloadedStrings
#-}

import qualified Graphics.UI.Webviewhs as WHS

main :: IO ()
main = do
  WHS.createWindowAndBlock
    WHS.WindowParams
      { WHS.windowParamsTitle      = "Test"
      , WHS.windowParamsUri        = "https://lettier.github.io"
      , WHS.windowParamsWidth      = 800
      , WHS.windowParamsHeight     = 600
      , WHS.windowParamsResizable  = True
      , WHS.windowParamsDebuggable = True
      }

If you want more control over the native desktop window, you could do something like this:

{-# LANGUAGE
    OverloadedStrings
  , QuasiQuotes
#-}

import Control.Monad
import Control.Concurrent
import Control.Concurrent.BoundedChan as CCBC
import Data.Maybe
import Data.Text
import qualified Data.Text.Lazy as DTL
import Data.Text.Format.Heavy
import Language.Javascript.JMacro
import qualified Clay
import qualified Graphics.UI.Webviewhs as WHS

main :: IO ()
main = do
  -- Create a channel to communicate between the main thread and another thread you'll create.
  -- This isn't necessary but it's a great way to communicate between threads.
  channel <- newBoundedChan 1

  -- withWindowLoop handles the creation, iteration, and deletion of the window.
  WHS.withWindowLoop

    -- Set the window creation params.
    WHS.WindowParams
      { WHS.windowParamsTitle      = "Test"
        -- This could be a localhost URL to your single-page application (SPA).
      , WHS.windowParamsUri        = "https://lettier.github.com"
      , WHS.windowParamsWidth      = 800
      , WHS.windowParamsHeight     = 600
      , WHS.windowParamsResizable  = True
      , WHS.windowParamsDebuggable = True -- Enables the Web Inspector if using WebKit.
      }

    -- webview allows you to specify a callback function that can be
    -- called from the JavaScript side.
    -- The callback receives a single string parameter.
    -- This could be unstructured text or unparsed JSON for example.
    -- You can just print what was received for now.
    (\ _window stringFromJavaScript -> print stringFromJavaScript)

    -- This function runs before the loop.
    (WHS.WithWindowLoopSetUp    (\ _window -> print "Setting up."))

    -- This function runs after the loop.
    (WHS.WithWindowLoopTearDown (\ _window -> print "Tearing down."))

    -- If you don't need to set up and/or tear down anything, you can do this.
    -- (WHS.WithWindowLoopSetUp    (void . return . const))
    -- (WHS.WithWindowLoopTearDown (void . return . const))

    -- This function is called continuously.
    -- Return True to continue the window loop or
    -- return False to exit the loop and destroy the window.
    $ \ window -> do

      -- webviewhs provides log and log'.
      -- log uses text-format-heavy which provides a
      -- "full-featured string formatting function, similar to Python's string.format."
      -- log' takes a simple Text string.
      -- According to webview, logging will print to
      -- "stderr, MacOS Console or [Windows] DebugView."
      let string = "world" :: Text
      WHS.log "Hello {string}!" [("string" :: DTL.Text, Variable string)]

      -- webview allows you to run JS inside the window.
      -- webviewhs comes with runJavaScript and runJavaScript'.
      -- runJavaScript uses JMacro which is a
      -- "simple DSL for lightweight (untyped) programmatic generation of Javascript."
      -- runJavaScript' takes a Text string which may or may not be valid JavaScript.
      let red = "red" :: Text
      _ <- WHS.runJavaScript
        window

        -- This changes the web page background color to red.
        -- Notice that you can use Haskell values inside the JavaScript and
        -- even use Haskell like syntax.
        [jmacro|
          fun setBackgroundColor color { document.body.style.backgroundColor = color; }
          setTimeout(
            \ -> setBackgroundColor `(red)`,
            5000
          );
        |]

      -- webview allows you to inject CSS into the window.
      -- webviewhs offers injectCss and injectCss'.
      -- injectCss uses Clay "a CSS preprocessor like LESS and Sass,
      -- but implemented as an embedded domain specific language (EDSL) in Haskell."
      -- injectCss' takes a Text string which may or may not be valid CSS.
      _ <- WHS.injectCss
        window

        -- This turns all <div> text blue.
        $ Clay.div Clay.?
          Clay.color "#0000ff"

      -- Inside the window loop, create a thread.
      _ <- forkIO $ do
        WHS.log' "Hello from inside a thread."

        -- When you're not in the main window UI thread, you'll need to call
        -- dispatchToMain if you want to interact with the window.
        -- dispatchToMain will run the given function in the main UI thread.
        -- Note that dispatchToMain runs the function asynchronously with no guarantee
        -- as to when it will run.
        WHS.dispatchToMain
          window
          $ \ window' -> do
            result <-
              WHS.runJavaScript
                window'

                -- This will randomly scroll the web page up and down.
                [jmacro|
                  if (Math.random() < 0.1) {
                    setTimeout(
                      function() {
                        window.scrollTo(0, Math.random() * window.innerHeight);
                      },
                      10000
                    );
                  }
                |]

            -- runJavaScript returns True if it was successful and
            -- False if something went wrong.
            -- Here is an attempt to write the result to the channel.
            void $ CCBC.tryWriteChan channel result

      -- Exit the loop if you read False from the channel.
      -- Note that tryReadChan does not block which is
      -- important when inside the window loop.
      fromMaybe True <$> tryReadChan channel

  -- At this point,
  -- the loop has been exited,
  -- the window has been destroyed,
  -- and the program will now exit.

For more ways to use webviewhs, take a look at the examples directory.

What if I don't want clay, jmacro, and text-format-heavy?

webviewhs has a light build flag that removes the dependencies clay, jmacro, and text-format-heavy. In some cases, using the light build flag can reduce the final binary size by 77%.

Note that the light build flag removes runJavaScript, injectCss, and log from the API. You can still use runJavaScript', injectCss', and log'.

If you're using stack, you can supply the light flag in the stack.yaml file.

flags:
  webviewhs:
    light: true

You can also supply the light flag on the command line like so.

stack build --flag webviewhs:light

If you're using cabal, you'll have to supply a constraint for all configure and install commands.

# For configure.
cabal configure  --constraint="webviewhs +light"

# For install.
cabal install -j --constraint="webviewhs +light"

There's currently no way to supply the constraint in the cabal file itself, however, there is an open issue about it.

For more information about using the light version of webviewhs, take a look at the examples-light directory.

What is the license?

For the webviewhs license information, see LICENSE. For the webview license information, see deps/webview/LICENSE.

Who wrote webviewhs?

(C) 2018 David Lettier
lettier.com

Who wrote webview?

Copyright (c) 2017 Serge Zaitsev

More Repositories

1

3d-game-shaders-for-beginners

๐ŸŽฎ A step-by-step guide to implementing SSAO, depth of field, lighting, normal mapping, and more for your 3D game.
C++
16,849
star
2

gifcurry

๐Ÿ˜Ž The open-source, Haskell-built video editor for GIF makers.
Haskell
1,301
star
3

movie-monad

๐Ÿ“บ A free and simple to use video player made with Haskell.
Haskell
419
star
4

lambda-lantern

๐Ÿง™ โ€Žโ€Ž A 3D game about functional programming patterns. Uses PureScript Native, C++, and Panda3D.
PureScript
159
star
5

ntpclient

NTP client.
C
130
star
6

lda-topic-modeling

A PureScript, browser-based implementation of LDA topic modeling.
PureScript
101
star
7

parsing-with-haskell-parser-combinators

๐Ÿ” A step-by-step guide to parsing using Haskell parser combinators.
Haskell
87
star
8

interactiveknn

Interactive K-Nearest Neighbors machine learning algorithm in JavaScript.
JavaScript
81
star
9

isosurface

Isosurface extraction using Marching Cubes and pure WebGL.
JavaScript
71
star
10

hacker-feud

๐Ÿ’ฅ A single page web game made with Svelte.
HTML
62
star
11

purescript-pop

๐Ÿ˜ƒ A functional reactive programming (FRP) demo created with PureScript events and behaviors.
PureScript
33
star
12

emoji-bingo

๐Ÿ˜„ A single page web game made with Svelte.
HTML
29
star
13

dnsclient

A simple DNS client similar to nslookup. Does not use any DNS libraries.
Python
26
star
14

blender-keymap-trainer

โŒจ๏ธ Digital flashcards for memorizing Blender's shortcut keys.
Svelte
25
star
15

webglbowling

A WebGL, browser-based bowling game that uses real-time physics.
JavaScript
24
star
16

lettier.github.io

HTML
21
star
17

interviewquestions

A collection of solutions to various technical interview questions.
Python
18
star
18

interactive-simple-linear-regression

A PureScript, browser-based implementation of simple linear regression.
PureScript
18
star
19

blendersim

Multi-agent robot simulator created with Blender.
Python
17
star
20

slackotron

A plugin extensible Slack bot.
Python
16
star
21

interactivekmeans

Interactive HTML canvas based implementation of k-means.
JavaScript
15
star
22

shortestpath

An interactive HTML5 canvas graph that shows the shortest path between any two nodes.
JavaScript
12
star
23

sierpinski

Explorable 3D Sierpinski tetrahedrons rendered using WebGL.
JavaScript
9
star
24

dubulrubul

Dual-sided, breakout-like 2D game using PhysicsJS, PubSubJS, EaselJS, and FunctionalJS.
JavaScript
8
star
25

poing

Browser based pong clone featuring a neuro-evolved AI opponent.
JavaScript
6
star
26

matrix-inverse-calculator

Input a square matrix and calculate its inverse if possible.
PureScript
5
star
27

bbautotune

Blender/Bullet automatic parameter tuning/learning.
TeX
4
star
28

telnetclientclone

A limited functionality Telnet client clone written in C.
C
3
star
29

boids

Boids steering behaviors created in 3D using the Panda3D API.
Python
3
star
30

webserver

A simple HTTP web server.
Python
3
star
31

wumpusworld

Wumpus World written in Java.
Java
3
star
32

cryptohoppershouter

Two tools for the automation of encrypting files and then later distributing them via email.
Python
3
star
33

simpl

Pong player utilizing a feedforward neural network and evolutionary algorithm.
JavaScript
3
star
34

webclient

A simple web client that retrieves files via HTTP from an HTTP server.
Python
2
star
35

smtpclient

A simple SMTP client that uses either port 25 or 587 with TLS authentication.
Python
2
star
36

chatserver

Simple chat server.
Python
2
star
37

bullytextsms

Code screen for DoSomething.org.
JavaScript
1
star
38

javatrafficlight

Java applet that displays and allows control of a crude traffic light.
Java
1
star
39

lettier.com

Code for the main website.
JavaScript
1
star
40

javaclock

Ticking analog clock made in Java.
Java
1
star
41

javacheckerboard

Java applet of a checker board.
1
star
42

jobjar

A job search web application.
JavaScript
1
star
43

javamancalaboard

Java applet that displays a Mancala board.
Java
1
star