on master help sign in
.travis.yml+40−24
since splitsnapshots
unifiedsplit
@@ -1,31 +1,47 @@
1−sudo: required
1+language: nix
2−services:
2+nix: 2.2.2
3− - docker
4
3
5−cache:
4+jobs:
6− directories:
5+ include:
7− - .cabal
6+ - stage: Build
8− - .ghc
7+ env: OS=linux GHCVER=ghc865
8+ - stage: Build
9+ env: OS=linux GHCVER=ghc881
10+ - env: OS=macos GHCVER=ghc865
11+ os: osx
12+ # Fix OSX, see https://travis-ci.community/t/cannot-use-nix-support-on-osx/2927
13+ language: generic
14+ before_install:
15+ - curl https://nixos.org/nix/install | sh
16+ - source /Users/travis/.nix-profile/etc/profile.d/nix.sh
17+ - env: OS=macos GHCVER=ghc881
18+ os: osx
19+ # Fix OSX, see https://travis-ci.community/t/cannot-use-nix-support-on-osx/2927
20+ language: generic
21+ before_install:
22+ - curl https://nixos.org/nix/install | sh
23+ - source /Users/travis/.nix-profile/etc/profile.d/nix.sh
9
24
10−env:
25+install:
11−# - CABALVER=1.24 GHCVER=7.10.3 OSVER=xenial
26+- sudo mkdir -p /etc/nix
12− - CABALVER=1.24 GHCVER=8.0.1 OSVER=xenial
27+- echo "substituters = https://cache.nixos.org https://hydra.iohk.io" | sudo tee -a /etc/nix/nix.conf > /dev/null
13− - CABALVER=1.24 GHCVER=8.0.2 OSVER=xenial
28+- echo "trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=" | sudo tee -a /etc/nix/nix.conf > /dev/null
14− - CABALVER=1.24 GHCVER=7.10.3 OSVER=trusty
15− - CABALVER=1.24 GHCVER=8.0.1 OSVER=trusty
16− - CABALVER=1.24 GHCVER=8.0.2 OSVER=trusty
17−
18−before_install:
19− - docker build -t ghc -f travis/$OSVER.Dockerfile travis
20
29
21script:
30script:
22− - docker run -v `pwd`:/build ghc
31+- nix-build --argstr haskellCompiler $GHCVER -A hsPkgs.jsaddle.components.library
23− sh -x -c "
32+- nix-build --argstr haskellCompiler $GHCVER -A hsPkgs.jsaddle-warp.components.library
24− apt-get install -y cabal-install-$CABALVER ghc-$GHCVER &&
33+- nix-build --argstr haskellCompiler $GHCVER -A hsPkgs.jsaddle-clib.components.library
25− export PATH=\$HOME/.cabal/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:/opt/alex/3.1.7/bin:/opt/happy/1.19.5/bin:\$PATH &&
34+- |
26− ./travis/build.sh"
35+ if [ "$OS" == "macos" ]; then
36+ nix-build --argstr haskellCompiler $GHCVER -A hsPkgs.jsaddle-wkwebview.components.library
37+ fi
38+# TODO try to find how to get working webkitgtk with nix on macOS
39+- |
40+ if [ "$OS" != "macos" ]; then
41+ nix-build --argstr haskellCompiler $GHCVER -A hsPkgs.jsaddle-webkit2gtk.components.library
42+ fi
43+
27notifications:
44notifications:
28 irc:
45 irc:
29 channels: "irc.freenode.net#ghcjs"
46 channels: "irc.freenode.net#ghcjs"
30− skip_join: true
31− email: true
47+ email: true
README.md+9−9
@@ -80,7 +80,7 @@ main = run 3708 $ do
80 appendChild newParagraph text
80 appendChild newParagraph text
81 appendChild body (Just newParagraph)
81 appendChild body (Just newParagraph)
82 return ()
82 return ()
83−
83+
84 -- Make an exit button
84 -- Make an exit button
85 exitMVar <- liftIO newEmptyMVar
85 exitMVar <- liftIO newEmptyMVar
86 Just exit <- createElement doc (Just "span")
86 Just exit <- createElement doc (Just "span")
@@ -111,8 +111,8 @@ There are a number of different JSaddle runners to choose from
111* [jsaddle-clib](https://hackage.haskell.org/package/jsaddle-clib) - C interface used to run JSaddle on Android using JNI.
111* [jsaddle-clib](https://hackage.haskell.org/package/jsaddle-clib) - C interface used to run JSaddle on Android using JNI.
112
112
113In all of these cases a web control or browser of some sort is used. An
113In all of these cases a web control or browser of some sort is used. An
114−[HTML file](https://github.com/ghcjs/jsaddle/blob/master/data/index.html)
114+[HTML file](./jsaddle/src/Language/Javascript/JSaddle/Run/Files.hs#L24)
115−and a [small JavaScript command interpreter](https://github.com/ghcjs/jsaddle/blob/master/data/jsaddle.js)
115+and a [small JavaScript command interpreter](./jsaddle/src/Language/Javascript/JSaddle/Run/Files.hs#L340)
116are loaded into it. Then the native GHC compiled JSaddle code runs. In order to interact with the browser
116are loaded into it. Then the native GHC compiled JSaddle code runs. In order to interact with the browser
117it sends commands to the JavaScript command interpreter. The mechanism for sending the commands differs
117it sends commands to the JavaScript command interpreter. The mechanism for sending the commands differs
118for the different runners, but they are always combined into batches and encoded in JSON.
118for the different runners, but they are always combined into batches and encoded in JSON.
@@ -123,7 +123,7 @@ JavaScript thread until the Haskell callback completes) or asynchronous.
123### Why use a JavaScript command interpreter?
123### Why use a JavaScript command interpreter?
124
124
125Older versions of JSaddle relied on the WebKit1 interface to WebKitGTK and JavaScriptCore that is only supported in older versions of
125Older versions of JSaddle relied on the WebKit1 interface to WebKitGTK and JavaScriptCore that is only supported in older versions of
126−WebKitGTK. With the newer WekKit2 interface this level of access is only available to WebKit Extensions.
126+WebKitGTK. With the newer WebKit2 interface this level of access is only available to WebKit Extensions.
127The general advice for people migrating from WebKit1 to WebKit2 seems to be to use JavaScript.
127The general advice for people migrating from WebKit1 to WebKit2 seems to be to use JavaScript.
128
128
129As a bonus we have been able to support a number of different platforms with the JavaScript command interpreter and it should
129As a bonus we have been able to support a number of different platforms with the JavaScript command interpreter and it should
@@ -137,8 +137,8 @@ The first five keys `[0..4]` are
137these values. Both the Haskell code and `jsaddle.js` can allocate new `JSVal` keys. The Haskell code allocates negative
137these values. Both the Haskell code and `jsaddle.js` can allocate new `JSVal` keys. The Haskell code allocates negative
138keys and `jsaddle.js` allocates positive keys to avoid clashing.
138keys and `jsaddle.js` allocates positive keys to avoid clashing.
139
139
140−The haskell code will not know the value of the to go with the key, but it will include it in commands to the server
140+The haskell code will not know the value to go with the key, but it will include it in commands to the server
141−that are sort of "hey call this function and and put the result in the map with this key"). This allows for the
141+that are sort of "hey call this function and put the result in the map with this key"). This allows for the
142lazy execution of the JSaddle code.
142lazy execution of the JSaddle code.
143
143
144A finalizer is added on the Haskell code and an asynchronous `FreeJSVal` command is automatically sent to `jsaddle.js`
144A finalizer is added on the Haskell code and an asynchronous `FreeJSVal` command is automatically sent to `jsaddle.js`
@@ -146,7 +146,7 @@ when the JSVal is no longer reachable. The `jsaddle.js` code then deletes the k
146
146
147### JSStrings
147### JSStrings
148
148
149−These are haskell `Text` type and so reside on the native side of the WebSocket. If you want to make avoid transferring large string values over the WebSocket use `toJSVal` to conevt it to a `JSVal`.
149+These are haskell `Text` type and so reside on the native side of the WebSocket. If you want to avoid transferring large string values over the WebSocket use `toJSVal` to convert it to a `JSVal`.
150
150
151### Lazy Execution
151### Lazy Execution
152
152
@@ -178,7 +178,7 @@ force all the pending asynchronous commands to be executed.
178It uses a handful of JS FFI calls to execute JavaScript functions indirectly. This indirection will be small compared to the overhead of the WebSockets approach (used when JSaddle is compiled with GHC), but it will be significant compared to hand crafted JS FFI calls.
178It uses a handful of JS FFI calls to execute JavaScript functions indirectly. This indirection will be small compared to the overhead of the WebSockets approach (used when JSaddle is compiled with GHC), but it will be significant compared to hand crafted JS FFI calls.
179
179
180For the best performance you may want to write both JS FFI and JSaddle wrappers
180For the best performance you may want to write both JS FFI and JSaddle wrappers
181−For your JavaScript code. This is the approach taken by `ghcjs-dom`.
181+for your JavaScript code. This is the approach taken by `ghcjs-dom`.
182
182
183For instance here is `getElementById` from the `ghcjs-dom-jsffi` (used by `ghcjs-dom` when compiled with GHCJS)
183For instance here is `getElementById` from the `ghcjs-dom-jsffi` (used by `ghcjs-dom` when compiled with GHCJS)
184
184
@@ -213,7 +213,7 @@ JSaddle does not support exceptions well. When compiled with GHCJS an exception
213at the point the exception is thrown.
213at the point the exception is thrown.
214
214
215When using GHC the Haskell executions will probably continue for a while before the exception is received at all by the Haskell code
215When using GHC the Haskell executions will probably continue for a while before the exception is received at all by the Haskell code
216−(because the lazy execution of the JS code). The exception will be thrown when the the next synchronous command is executed.
216+(because the lazy execution of the JS code). The exception will be thrown when the next synchronous command is executed.
217When it reaches the synchronous command a haskell type JSException will be thrown (this may not be the thread that initiated the
217When it reaches the synchronous command a haskell type JSException will be thrown (this may not be the thread that initiated the
218command that caused the exception). You can use `syncPoint` and `syncAfter` to force the exception to be thrown.
218command that caused the exception). You can use `syncPoint` and `syncAfter` to force the exception to be thrown.
219There are `JSM` versions of `catch` and `bracket` that also include a `syncPoint` call.
219There are `JSM` versions of `catch` and `bracket` that also include a `syncPoint` call.
cabal.project+3−35
@@ -1,42 +1,10 @@
1−flags: -overloaded-methods -overloaded-signals -overloaded-properties
2−
3packages:
1packages:
4 jsaddle/
2 jsaddle/
5 jsaddle-warp/
3 jsaddle-warp/
6 jsaddle-wkwebview/
4 jsaddle-wkwebview/
7−-- jsaddle-webkitgtk/
8 jsaddle-webkit2gtk/
5 jsaddle-webkit2gtk/
9 jsaddle-clib/
6 jsaddle-clib/
10
7
11−package gi-atk
8+constraints: haskell-gi-overloading == 0.0
12− flags: -overloaded-methods -overloaded-signals -overloaded-properties
9+
13−package gi-cairo
10+allow-newer: websockets:random, splitmix:time, *:time, *:unix, *:process, stm:base
14− flags: -overloaded-methods -overloaded-signals -overloaded-properties
15−package gi-gdk
16− flags: -overloaded-methods -overloaded-signals -overloaded-properties
17−package gi-gdkpixbuf
18− flags: -overloaded-methods -overloaded-signals -overloaded-properties
19−package gi-gio
20− flags: -overloaded-methods -overloaded-signals -overloaded-properties
21−package gi-glib
22− flags: -overloaded-methods -overloaded-signals -overloaded-properties
23−package gi-gobject
24− flags: -overloaded-methods -overloaded-signals -overloaded-properties
25−package gi-gtk
26− flags: -overloaded-methods -overloaded-signals -overloaded-properties
27−package gi-gtk-hs
28− flags: -overloaded-methods -overloaded-signals -overloaded-properties
29−package gi-gtkosxapplication
30− flags: -overloaded-methods -overloaded-signals -overloaded-properties
31−package gi-gtksource
32− flags: -overloaded-methods -overloaded-signals -overloaded-properties
33−package gi-javascriptcore
34− flags: -overloaded-methods -overloaded-signals -overloaded-properties
35−package gi-pango
36− flags: -overloaded-methods -overloaded-signals -overloaded-properties
37−package gi-soup
38− flags: -overloaded-methods -overloaded-signals -overloaded-properties
39−package gi-webkit
40− flags: -overloaded-methods -overloaded-signals -overloaded-properties
41−package gi-webkit2
42− flags: -overloaded-methods -overloaded-signals -overloaded-properties
default.nixdeleted−8
@@ -1,8 +0,0 @@
1−haskellPackages: {
2− jsaddle = haskellPackages.callPackage ./jsaddle {};
3− jsaddle-warp = haskellPackages.callPackage ./jsaddle-warp {};
4− jsaddle-wkwebview = haskellPackages.callPackage ./jsaddle-wkwebview {};
5− jsaddle-webkit2gtk = haskellPackages.callPackage ./jsaddle-webkit2gtk {};
6− jsaddle-webkitgtk = haskellPackages.callPackage ./jsaddle-webkitgtk {};
7− jsaddle-clib = haskellPackages.callPackage ./jsaddle-clib {};
8−}
jsaddle-clib/default.nixdeleted−9
@@ -1,9 +0,0 @@
1−{ mkDerivation, aeson, base, bytestring, data-default, jsaddle, stdenv, text }:
2−mkDerivation {
3− pname = "jsaddle-clib";
4− version = "0.9.0.0";
5− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
6− libraryHaskellDepends = [ aeson base bytestring data-default jsaddle text ];
7− description = "Interface for JavaScript that works with GHCJS and GHC";
8− license = stdenv.lib.licenses.mit;
9−}
jsaddle-clib/jsaddle-clib.cabal+4−3
@@ -1,5 +1,5 @@
1name: jsaddle-clib
1name: jsaddle-clib
2−version: 0.9.0.0
2+version: 0.9.8.0
3cabal-version: >=1.10
3cabal-version: >=1.10
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
@@ -21,8 +21,9 @@ library
21 Language.Javascript.JSaddle.CLib
21 Language.Javascript.JSaddle.CLib
22 Language.Javascript.JSaddle.CLib.Internal
22 Language.Javascript.JSaddle.CLib.Internal
23 build-depends:
23 build-depends:
24− aeson >=0.8.0.2 && <1.3,
24+ aeson >=0.8.0.2 && <1.6,
25 base <5,
25 base <5,
26+ base-compat >=0.9.0 && <0.12,
26 bytestring >=0.10.6.0 && <0.11,
27 bytestring >=0.10.6.0 && <0.11,
27 jsaddle >= 0.9.0.0 && <0.10,
28 jsaddle >= 0.9.0.0 && <0.10,
28 data-default,
29 data-default,
@@ -32,7 +33,7 @@ library
32 Include-dirs: cbits/include
33 Include-dirs: cbits/include
33 Includes: jsaddle.h
34 Includes: jsaddle.h
34 Install-includes: jsaddle.h
35 Install-includes: jsaddle.h
35− ghc-options: -ferror-spans -Wall -Werror
36+ ghc-options: -ferror-spans -Wall
36 if impl(ghcjs)
37 if impl(ghcjs)
37 hs-source-dirs: src-ghcjs
38 hs-source-dirs: src-ghcjs
38 else
39 else
jsaddle-clib/src-ghc/Language/Javascript/JSaddle/CLib.hs+3−1
@@ -8,6 +8,9 @@ module Language.Javascript.JSaddle.CLib
8 , appConfigToAppCallbacks
8 , appConfigToAppCallbacks
9 ) where
9 ) where
10
10
11+import Prelude ()
12+import Prelude.Compat
13+
11import Control.Monad (void)
14import Control.Monad (void)
12import Control.Concurrent (forkIO)
15import Control.Concurrent (forkIO)
13
16
@@ -16,7 +19,6 @@ import Data.ByteString (useAsCString, packCString)
16import Data.ByteString.Char8 (unpack)
19import Data.ByteString.Char8 (unpack)
17import Data.ByteString.Lazy (ByteString, toStrict, fromStrict)
20import Data.ByteString.Lazy (ByteString, toStrict, fromStrict)
18import Data.Default (def, Default)
21import Data.Default (def, Default)
19−import Data.Monoid ((<>))
20import Data.Text (Text)
22import Data.Text (Text)
21import qualified Data.Text.Encoding as T
23import qualified Data.Text.Encoding as T
22
24
jsaddle-warp/default.nixdeleted−25
@@ -1,25 +0,0 @@
1−{ mkDerivation, aeson, base, bytestring, containers, deepseq
2−, doctest, filepath, foreign-store, ghc-prim, http-types, jsaddle
3−, lens, network, primitive, process, QuickCheck, ref-tf, stdenv
4−, stm, text, time, transformers, uuid, uuid-types, wai
5−, wai-websockets, warp, webdriver, websockets
6−}:
7−mkDerivation {
8− pname = "jsaddle-warp";
9− version = "0.9.4.0";
10− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
11− libraryHaskellDepends = [
12− aeson base bytestring containers foreign-store http-types jsaddle
13− stm text time transformers uuid uuid-types wai wai-websockets warp
14− websockets
15− ];
16− testHaskellDepends = [
17− aeson base bytestring containers deepseq doctest filepath ghc-prim
18− http-types jsaddle lens network primitive process QuickCheck ref-tf
19− stm text time transformers wai wai-websockets warp webdriver
20− websockets
21− ];
22− testTarget = "--test-option=${jsaddle.src}";
23− description = "Interface for JavaScript that works with GHCJS and GHC";
24− license = stdenv.lib.licenses.mit;
25−}
jsaddle-warp/jsaddle-warp.cabal+15−9
@@ -1,5 +1,5 @@
1name: jsaddle-warp
1name: jsaddle-warp
2−version: 0.9.5.0
2+version: 0.9.8.0
3cabal-version: >=1.10
3cabal-version: >=1.10
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
@@ -10,7 +10,7 @@ description:
10 This package provides an EDSL for calling JavaScript that
10 This package provides an EDSL for calling JavaScript that
11 can be used both from GHCJS and GHC. When using GHC
11 can be used both from GHCJS and GHC. When using GHC
12 the application is run using Warp and WebSockets to
12 the application is run using Warp and WebSockets to
13− drive a small JavaScipt helper.
13+ drive a small JavaScript helper.
14category: Web, Javascript
14category: Web, Javascript
15author: Hamish Mackenzie
15author: Hamish Mackenzie
16
16
@@ -24,20 +24,22 @@ library
24 if !impl(ghcjs -any)
24 if !impl(ghcjs -any)
25 exposed-modules:
25 exposed-modules:
26 Language.Javascript.JSaddle.WebSockets
26 Language.Javascript.JSaddle.WebSockets
27+ other-modules:
28+ Language.Javascript.JSaddle.WebSockets.Compat
27 build-depends:
29 build-depends:
28− aeson >=0.8.0.2 && <1.3,
30+ aeson >=0.8.0.2 && <1.6,
29 bytestring >=0.10.6.0 && <0.11,
31 bytestring >=0.10.6.0 && <0.11,
30− containers >=0.5.6.2 && <0.6,
32+ containers >=0.5.6.2 && <0.7,
31 foreign-store >=0.2 && <0.3,
33 foreign-store >=0.2 && <0.3,
32 http-types >=0.8.6 && <0.13,
34 http-types >=0.8.6 && <0.13,
33 jsaddle >=0.9.4.0 && <0.10,
35 jsaddle >=0.9.4.0 && <0.10,
34− stm >=2.4.4 && <2.5,
36+ stm >=2.4.4 && <2.6,
35 text >=1.2.1.3 && <1.3,
37 text >=1.2.1.3 && <1.3,
36− time >=1.5.0.1 && <1.9,
38+ time >=1.5.0.1 && <1.11,
37 transformers >=0.4.2.0 && <0.6,
39 transformers >=0.4.2.0 && <0.6,
38 wai >=3.0.3.0 && <3.3,
40 wai >=3.0.3.0 && <3.3,
39 wai-websockets >=3.0.0.6 && <3.1,
41 wai-websockets >=3.0.0.6 && <3.1,
40− warp >=3.1.2 && <3.3,
42+ warp >=3.1.2 && <3.4,
41 websockets >=0.9.5.0 && <0.13
43 websockets >=0.9.5.0 && <0.13
42 exposed-modules:
44 exposed-modules:
43 Language.Javascript.JSaddle.Warp
45 Language.Javascript.JSaddle.Warp
@@ -57,8 +59,10 @@ test-suite test-tool
57 bytestring -any,
59 bytestring -any,
58 containers -any,
60 containers -any,
59 deepseq -any,
61 deepseq -any,
60− doctest >=0.10.1 && <0.17,
62+ doctest >=0.10.1 && <0.19,
63+ exceptions -any,
61 filepath >=1.4.0.0 && <1.5,
64 filepath >=1.4.0.0 && <1.5,
65+ foreign-store -any,
62 ghc-prim -any,
66 ghc-prim -any,
63 http-types -any,
67 http-types -any,
64 jsaddle -any,
68 jsaddle -any,
@@ -68,14 +72,16 @@ test-suite test-tool
68 ref-tf -any,
72 ref-tf -any,
69 primitive -any,
73 primitive -any,
70 process >=1.2.3.0 && <1.7,
74 process >=1.2.3.0 && <1.7,
75+ random -any,
71 stm -any,
76 stm -any,
72 text -any,
77 text -any,
73 time -any,
78 time -any,
74 transformers -any,
79 transformers -any,
80+ unliftio-core -any,
75 wai -any,
81 wai -any,
76 wai-websockets -any,
82 wai-websockets -any,
77 warp -any,
83 warp -any,
78− webdriver >=0.8.4 && <0.9,
84+ webdriver >=0.8.4 && <0.10,
79 websockets -any
85 websockets -any
80 type: exitcode-stdio-1.0
86 type: exitcode-stdio-1.0
81 main-is: DocTest.hs
87 main-is: DocTest.hs
jsaddle-warp/src/Language/Javascript/JSaddle/Test.hs+13−12
@@ -17,21 +17,22 @@ module Language.Javascript.JSaddle.Test (
17 , listWindowProperties
17 , listWindowProperties
18) where
18) where
19
19
20−import Control.Applicative
21import Prelude hiding((!!), catch)
20import Prelude hiding((!!), catch)
22−import Control.Monad.Trans.Reader (runReaderT)
21+import Control.Applicative
23−import Language.Javascript.JSaddle
22+import Control.Concurrent (threadDelay, forkIO, ThreadId)
24−import qualified Data.Text as T
25−import Control.Monad.IO.Class (MonadIO(..))
26−import Control.Monad (forever, forM)
27−import Control.Lens.Getter ((^.))
28−import Data.Monoid ((<>))
29import Control.Concurrent.MVar
23import Control.Concurrent.MVar
30 (tryTakeMVar, putMVar, takeMVar, newEmptyMVar, MVar)
24 (tryTakeMVar, putMVar, takeMVar, newEmptyMVar, MVar)
31−import System.IO.Unsafe (unsafePerformIO)
25+import Control.Lens.Getter ((^.))
32−import Control.Concurrent (threadDelay, forkIO, ThreadId)
26+import Control.Monad (forever, forM)
27+import Control.Monad.IO.Class (MonadIO(..))
28+import Control.Monad.Trans.Reader (runReaderT)
29+import Data.Monoid ((<>))
33import Data.Text (Text)
30import Data.Text (Text)
31+import qualified Data.Text as T
32+import Language.Javascript.JSaddle
34import Language.Javascript.JSaddle.Warp (run)
33import Language.Javascript.JSaddle.Warp (run)
34+import System.IO.Unsafe (unsafePerformIO)
35+import System.Timeout (timeout)
35
36
36context :: MVar JSContextRef
37context :: MVar JSContextRef
37context = unsafePerformIO newEmptyMVar
38context = unsafePerformIO newEmptyMVar
@@ -52,12 +53,12 @@ startServer =
52
53
53-- >>> testJSaddle $ ((global ^. js "console" . js "log") # ["Hello"])
54-- >>> testJSaddle $ ((global ^. js "console" . js "log") # ["Hello"])
54testJSaddle :: ToJSVal val => JSM val -> IO ()
55testJSaddle :: ToJSVal val => JSM val -> IO ()
55−testJSaddle f = do
56+testJSaddle f = timeout 10000000 (do
56 startServer
57 startServer
57 c <- takeMVar context
58 c <- takeMVar context
58 runReaderT (unJSM $ (f >>= valToText >>= liftIO . putStrLn . T.unpack)
59 runReaderT (unJSM $ (f >>= valToText >>= liftIO . putStrLn . T.unpack)
59 `catch` \ (JSException e) -> valToText e >>= liftIO . putStrLn . T.unpack) c
60 `catch` \ (JSException e) -> valToText e >>= liftIO . putStrLn . T.unpack) c
60− putMVar context c
61+ putMVar context c) >>= maybe (putStrLn "testJSaddle timed out") return
61
62
62debugLog :: String -> IO ()
63debugLog :: String -> IO ()
63debugLog _ = return ()
64debugLog _ = return ()
jsaddle-warp/src/Language/Javascript/JSaddle/WebSockets.hs+62−26
@@ -20,10 +20,12 @@ module Language.Javascript.JSaddle.WebSockets (
20 , jsaddleApp
20 , jsaddleApp
21 , jsaddleWithAppOr
21 , jsaddleWithAppOr
22 , jsaddleAppWithJs
22 , jsaddleAppWithJs
23+ , jsaddleAppWithJsOr
23 , jsaddleAppPartial
24 , jsaddleAppPartial
24 , jsaddleJs
25 , jsaddleJs
25 , jsaddleJs'
26 , jsaddleJs'
26 , debug
27 , debug
28+ , debugOr
27 , debugWrapper
29 , debugWrapper
28) where
30) where
29
31
@@ -58,45 +60,57 @@ import qualified Data.Map as M (empty, insert, lookup)
58import Data.IORef
60import Data.IORef
59 (readIORef, newIORef, atomicModifyIORef')
61 (readIORef, newIORef, atomicModifyIORef')
60import Data.ByteString.Lazy (ByteString)
62import Data.ByteString.Lazy (ByteString)
61−import qualified Data.ByteString.Lazy as LBS (stripPrefix)
63+import qualified Data.ByteString.Lazy as LBS
64+ (toStrict, stripPrefix)
62import Control.Concurrent.MVar
65import Control.Concurrent.MVar
63 (tryTakeMVar, MVar, tryPutMVar, modifyMVar_, putMVar, takeMVar,
66 (tryTakeMVar, MVar, tryPutMVar, modifyMVar_, putMVar, takeMVar,
64 readMVar, newMVar, newEmptyMVar, modifyMVar)
67 readMVar, newMVar, newEmptyMVar, modifyMVar)
65import Network.Wai.Handler.Warp
68import Network.Wai.Handler.Warp
66 (defaultSettings, setTimeout, setPort, runSettings)
69 (defaultSettings, setTimeout, setPort, runSettings)
67−import Foreign.Store (newStore, readStore, lookupStore, writeStore, Store(..))
70+import Foreign.Store (readStore, lookupStore, writeStore, Store(..))
68import Language.Javascript.JSaddle (askJSM)
71import Language.Javascript.JSaddle (askJSM)
69import Control.Monad.IO.Class (MonadIO(..))
72import Control.Monad.IO.Class (MonadIO(..))
70
73
71import Language.Javascript.JSaddle.WebSockets.Compat (getTextMessageByteString)
74import Language.Javascript.JSaddle.WebSockets.Compat (getTextMessageByteString)
75+import qualified Data.Text.Encoding as T (decodeUtf8)
72
76
73jsaddleOr :: ConnectionOptions -> JSM () -> Application -> IO Application
77jsaddleOr :: ConnectionOptions -> JSM () -> Application -> IO Application
74jsaddleOr opts entryPoint otherApp = do
78jsaddleOr opts entryPoint otherApp = do
75 syncHandlers <- newIORef M.empty
79 syncHandlers <- newIORef M.empty
80+ asyncHandlers <- newIORef M.empty
76 let wsApp :: ServerApp
81 let wsApp :: ServerApp
77 wsApp pending_conn = do
82 wsApp pending_conn = do
78 conn <- acceptRequest pending_conn
83 conn <- acceptRequest pending_conn
84+ initMsg <- receiveDataMessage conn
85+ case getTextMessageByteString initMsg of
86+ Just "" -> do
79− rec (processResult, processSyncResult, start) <- runJavaScript (sendTextData conn . encode) $ do
87+ rec (processResult, processSyncResult, start) <- runJavaScript (sendTextData conn . encode) $ do
80− syncKey <- T.pack . show . contextId <$> askJSM
88+ syncKey <- T.pack . show . contextId <$> askJSM
81− liftIO $ atomicModifyIORef' syncHandlers (\m -> (M.insert syncKey processSyncResult m, ()))
89+ liftIO $ atomicModifyIORef' syncHandlers (\m -> (M.insert syncKey processSyncResult m, ()))
90+ liftIO $ atomicModifyIORef' asyncHandlers (\m -> (M.insert syncKey processResult m, ()))
82− liftIO $ sendTextData conn (encode syncKey)
91+ liftIO $ sendTextData conn (encode syncKey)
83− entryPoint
92+ entryPoint
84− _ <- forkIO . forever $
93+ start
85− receiveDataMessage conn >>= \msg -> case getTextMessageByteString msg of
94+ waitTillClosed conn
86− Just t ->
95+ Just syncKey ->
96+ M.lookup (T.decodeUtf8 $ LBS.toStrict syncKey) <$> readIORef syncHandlers >>= \case
97+ Nothing -> error "jsaddle missing sync message handler"
98+ Just processResult ->
99+ forever $
100+ receiveDataMessage conn >>= \msg -> case getTextMessageByteString msg of
101+ Just t ->
87− case decode t of
102+ case decode t of
88− Nothing -> error $ "jsaddle Results decode failed : " <> show t
103+ Nothing -> error $ "jsaddle Results decode failed : " <> show t
89− Just r -> processResult r
104+ Just r -> processResult r
90− _ -> error "jsaddle WebSocket unexpected binary data"
105+ _ -> error "jsaddle WebSocket unexpected binary data"
91− start
106+ _ -> error "jsaddle WebSocket unexpected binary data"
92− waitTillClosed conn
93
107
94 -- Based on Network.WebSocket.forkPingThread
108 -- Based on Network.WebSocket.forkPingThread
95 waitTillClosed conn = ignore `handle` go 1
109 waitTillClosed conn = ignore `handle` go 1
96 where
110 where
97 go :: Int -> IO ()
111 go :: Int -> IO ()
98 go i = do
112 go i = do
99− threadDelay (1 * 1000 * 1000)
113+ threadDelay (10 * 1000 * 1000)
100 sendPing conn (T.pack $ show i)
114 sendPing conn (T.pack $ show i)
101 go (i + 1)
115 go (i + 1)
102
116
@@ -129,9 +143,14 @@ jsaddleApp = jsaddleAppWithJs $ jsaddleJs False
129
143
130jsaddleAppWithJs :: ByteString -> Application
144jsaddleAppWithJs :: ByteString -> Application
131jsaddleAppWithJs js req sendResponse =
145jsaddleAppWithJs js req sendResponse =
132− fromMaybe
146+ jsaddleAppWithJsOr js
133− (sendResponse $ W.responseLBS H.status403 [("Content-Type", "text/plain")] "Forbidden")
147+ (\_ _ -> sendResponse $ W.responseLBS H.status403 [("Content-Type", "text/plain")] "Forbidden")
148+ req sendResponse
149+
150+jsaddleAppWithJsOr :: ByteString -> Application -> Application
151+jsaddleAppWithJsOr js otherApp req sendResponse =
152+ fromMaybe (otherApp req sendResponse)
134− (jsaddleAppPartialWithJs js req sendResponse)
153+ (jsaddleAppPartialWithJs js req sendResponse)
135
154
136jsaddleWithAppOr :: ConnectionOptions -> JSM () -> Application -> IO Application
155jsaddleWithAppOr :: ConnectionOptions -> JSM () -> Application -> IO Application
137jsaddleWithAppOr opts entryPoint otherApp = jsaddleOr opts entryPoint $ \req sendResponse ->
156jsaddleWithAppOr opts entryPoint otherApp = jsaddleOr opts entryPoint $ \req sendResponse ->
@@ -157,7 +176,7 @@ jsaddleJs = jsaddleJs' Nothing
157-- sed -e 's|\\|\\\\|g' -e 's|^| \\|' -e 's|$|\\n\\|' -e 's|"|\\"|g' data/jsaddle.js | pbcopy
176-- sed -e 's|\\|\\\\|g' -e 's|^| \\|' -e 's|$|\\n\\|' -e 's|"|\\"|g' data/jsaddle.js | pbcopy
158jsaddleJs' :: Maybe ByteString -> Bool -> ByteString
177jsaddleJs' :: Maybe ByteString -> Bool -> ByteString
159jsaddleJs' jsaddleUri refreshOnLoad = "\
178jsaddleJs' jsaddleUri refreshOnLoad = "\
160− \if(typeof global !== \"undefined\") {\n\
179+ \if(typeof global !== \"undefined\" && typeof require === \"function\") {\n\
161 \ global.window = global;\n\
180 \ global.window = global;\n\
162 \ global.WebSocket = require('ws');\n\
181 \ global.WebSocket = require('ws');\n\
163 \}\n\
182 \}\n\
@@ -169,20 +188,30 @@ jsaddleJs' jsaddleUri refreshOnLoad = "\
169 (jsaddleUri >>= LBS.stripPrefix "http")
188 (jsaddleUri >>= LBS.stripPrefix "http")
170 <> ";\n\
189 <> ";\n\
171 \\n\
190 \\n\
172− \ var ws = new WebSocket(wsaddress);\n\
191+ \ var ws0 = new WebSocket(wsaddress);\n\
173 \ var syncKey = \"\";\n\
192 \ var syncKey = \"\";\n\
174 \\n\
193 \\n\
175− \ ws.onopen = function(e) {\n\
194+ \ ws0.onopen = function(e) {\n\
195+ \ ws0.send(\"\");\n\
196+ \ var initialResults = [];\n\
197+ \ var ws = {send: function(m) {initialResults.push(m);}};\n\
176 \ " <> initState <> "\n\
198 \ " <> initState <> "\n\
177 \\n\
199 \\n\
178− \ ws.onmessage = function(e) {\n\
200+ \ ws0.onmessage = function(e) {\n\
179 \ var batch = JSON.parse(e.data);\n\
201 \ var batch = JSON.parse(e.data);\n\
180 \ if(inCallback > 0) {\n\
202 \ if(inCallback > 0) {\n\
181 \ asyncBatch = batch;\n\
203 \ asyncBatch = batch;\n\
182 \ return;\n\
204 \ return;\n\
183 \ }\n\
205 \ }\n\
184 \ if(typeof batch === \"string\") {\n\
206 \ if(typeof batch === \"string\") {\n\
185− \ syncKey = batch;\n" <>
207+ \ syncKey = batch;\n\
208+ \ var ws1 = new WebSocket(wsaddress);\n\
209+ \ ws1.onopen = function(e) {\n\
210+ \ ws1.send(syncKey);\n\
211+ \ initialResults.forEach(function(m){ ws1.send(m); });\n\
212+ \ initialResults = null;\n\
213+ \ ws = ws1;\n\
214+ \ }\n" <>
186 (if refreshOnLoad
215 (if refreshOnLoad
187 then " var xhr = new XMLHttpRequest();\n\
216 then " var xhr = new XMLHttpRequest();\n\
188 \ xhr.open('POST', '/reload/'+syncKey, true);\n\
217 \ xhr.open('POST', '/reload/'+syncKey, true);\n\
@@ -204,7 +233,7 @@ jsaddleJs' jsaddleUri refreshOnLoad = "\
204 \ return JSON.parse(xhr.response);})()")) <> "\
233 \ return JSON.parse(xhr.response);})()")) <> "\
205 \ };\n\
234 \ };\n\
206 \ };\n\
235 \ };\n\
207− \ ws.onerror = function() {\n\
236+ \ ws0.onerror = function() {\n\
208 \ setTimeout(connect, 1000);\n\
237 \ setTimeout(connect, 1000);\n\
209 \ };\n\
238 \ };\n\
210 \}\n\
239 \}\n\
@@ -223,6 +252,13 @@ debug port f = do
223 jsaddleOr defaultConnectionOptions (registerContext >> f >> syncPoint) (withRefresh $ jsaddleAppWithJs $ jsaddleJs True)
252 jsaddleOr defaultConnectionOptions (registerContext >> f >> syncPoint) (withRefresh $ jsaddleAppWithJs $ jsaddleJs True)
224 putStrLn $ "<a href=\"http://localhost:" <> show port <> "\">run</a>"
253 putStrLn $ "<a href=\"http://localhost:" <> show port <> "\">run</a>"
225
254
255+debugOr :: Int -> JSM () -> Application -> IO ()
256+debugOr port f b = do
257+ debugWrapper $ \withRefresh registerContext ->
258+ runSettings (setPort port (setTimeout 3600 defaultSettings)) =<<
259+ jsaddleOr defaultConnectionOptions (registerContext >> f >> syncPoint) (withRefresh $ jsaddleAppWithJsOr (jsaddleJs True) b)
260+ putStrLn $ "<a href=\"http://localhost:" <> show port <> "\">run</a>"
261+
226refreshMiddleware :: ((Response -> IO ResponseReceived) -> IO ResponseReceived) -> Middleware
262refreshMiddleware :: ((Response -> IO ResponseReceived) -> IO ResponseReceived) -> Middleware
227refreshMiddleware refresh otherApp req sendResponse = case (W.requestMethod req, W.pathInfo req) of
263refreshMiddleware refresh otherApp req sendResponse = case (W.requestMethod req, W.pathInfo req) of
228 ("POST", ["reload", _syncKey]) -> refresh sendResponse
264 ("POST", ["reload", _syncKey]) -> refresh sendResponse
jsaddle-warp/tests/DocTest.hs+20−7
@@ -11,18 +11,17 @@ import System.IO (stderr, BufferMode(..), stdout, hSetBuffering)
11import System.FilePath ((</>))
11import System.FilePath ((</>))
12import System.Exit (exitFailure, exitWith, ExitCode(..))
12import System.Exit (exitFailure, exitWith, ExitCode(..))
13import System.Process (readProcess, system)
13import System.Process (readProcess, system)
14−import Control.Concurrent (forkIO)
14+import Control.Concurrent
15+ (takeMVar, newEmptyMVar, forkIO, threadDelay, putMVar)
15import Control.Monad (void)
16import Control.Monad (void)
16import Control.Monad.IO.Class (MonadIO(..))
17import Control.Monad.IO.Class (MonadIO(..))
17import Data.Monoid ((<>))
18import Data.Monoid ((<>))
18import System.Environment (getArgs)
19import System.Environment (getArgs)
19−import Language.Javascript.JSaddle.Run.Files (jsaddleJs)
20−import qualified Data.ByteString.Lazy.Char8 as BS (unpack)
21import Test.WebDriver (runSession, defaultConfig, openPage, closeSession)
20import Test.WebDriver (runSession, defaultConfig, openPage, closeSession)
22
21
23main :: IO ()
22main :: IO ()
24main = do
23main = do
25− putStrLn "Hello"
24+ putStrLn "Testing JSaddle"
26 jsaddlePath <- getArgs >>= \case
25 jsaddlePath <- getArgs >>= \case
27 [arg] -> return arg
26 [arg] -> return arg
28 _ -> do
27 _ -> do
@@ -30,14 +29,18 @@ main = do
30 exitFailure
29 exitFailure
31 hSetBuffering stdout LineBuffering
30 hSetBuffering stdout LineBuffering
32 hSetBuffering stderr LineBuffering
31 hSetBuffering stderr LineBuffering
32+ putStrLn "Checking for phantomjs"
33 node <- system "phantomjs --version" >>= \case
33 node <- system "phantomjs --version" >>= \case
34 ExitSuccess -> return ()
34 ExitSuccess -> return ()
35 e -> do
35 e -> do
36 putStrLn "phantomjs not found"
36 putStrLn "phantomjs not found"
37 exitWith e
37 exitWith e
38+ putStrLn "Starting phantomjs"
38− forkIO . void $ readProcess "phantomjs" ["--webdriver=4444"] (BS.unpack jsaddleJs) >>= putStr
39+ forkIO . void $ readProcess "phantomjs" ["--webdriver=4444"] "" >>= putStr
39− runSession defaultConfig $ do
40+ threadDelay 5000000
40− openPage "http://localhost:3709"
41+ putStrLn "Running Tests"
42+ done <- newEmptyMVar
43+ forkIO $ do
41 liftIO $ doctest [
44 liftIO $ doctest [
42 "-hide-all-packages",
45 "-hide-all-packages",
43 "-package=base-" ++ VERSION_base,
46 "-package=base-" ++ VERSION_base,
@@ -61,6 +64,10 @@ main = do
61 "-package=ref-tf-" ++ VERSION_ref_tf,
64 "-package=ref-tf-" ++ VERSION_ref_tf,
62 "-package=deepseq-" ++ VERSION_deepseq,
65 "-package=deepseq-" ++ VERSION_deepseq,
63 "-package=ghc-prim-" ++ VERSION_ghc_prim,
66 "-package=ghc-prim-" ++ VERSION_ghc_prim,
67+ "-package=exceptions-" ++ VERSION_exceptions,
68+ "-package=unliftio-core-" ++ VERSION_unliftio_core,
69+ "-package=random-" ++ VERSION_random,
70+ "-package=foreign-store-" ++ VERSION_foreign_store,
64 "-i" <> "src",
71 "-i" <> "src",
65 "-i" <> "src-ghc",
72 "-i" <> "src-ghc",
66 "src/Language/Javascript/JSaddle/Test.hs",
73 "src/Language/Javascript/JSaddle/Test.hs",
@@ -83,6 +90,7 @@ main = do
83 jsaddlePath </> "src/Language/Javascript/JSaddle/Arguments.hs",
90 jsaddlePath </> "src/Language/Javascript/JSaddle/Arguments.hs",
84 jsaddlePath </> "src/Language/Javascript/JSaddle/Classes.hs",
91 jsaddlePath </> "src/Language/Javascript/JSaddle/Classes.hs",
85 jsaddlePath </> "src/Language/Javascript/JSaddle/Classes/Internal.hs",
92 jsaddlePath </> "src/Language/Javascript/JSaddle/Classes/Internal.hs",
93+ jsaddlePath </> "src/Language/Javascript/JSaddle/Debug.hs",
86 jsaddlePath </> "src/Language/Javascript/JSaddle/Evaluate.hs",
94 jsaddlePath </> "src/Language/Javascript/JSaddle/Evaluate.hs",
87 jsaddlePath </> "src/Language/Javascript/JSaddle/Exception.hs",
95 jsaddlePath </> "src/Language/Javascript/JSaddle/Exception.hs",
88 jsaddlePath </> "src/Language/Javascript/JSaddle/Monad.hs",
96 jsaddlePath </> "src/Language/Javascript/JSaddle/Monad.hs",
@@ -96,4 +104,9 @@ main = do
96 jsaddlePath </> "src/Language/Javascript/JSaddle/String.hs",
104 jsaddlePath </> "src/Language/Javascript/JSaddle/String.hs",
97 jsaddlePath </> "src/Language/Javascript/JSaddle/Types.hs",
105 jsaddlePath </> "src/Language/Javascript/JSaddle/Types.hs",
98 jsaddlePath </> "src/Language/Javascript/JSaddle/Value.hs" ]
106 jsaddlePath </> "src/Language/Javascript/JSaddle/Value.hs" ]
107+ putMVar done ()
108+ threadDelay 5000000
109+ runSession defaultConfig $ do
110+ openPage "http://127.0.0.1:3709"
111+ liftIO $ takeMVar done
99 closeSession
112 closeSession
jsaddle-webkit2gtk/default.nixdeleted−16
@@ -1,16 +0,0 @@
1−{ mkDerivation, aeson, base, bytestring, directory, gi-gio, gi-glib
2−, gi-gtk, gi-javascriptcore, gi-webkit2, haskell-gi-base, jsaddle
3−, stdenv, text, unix, webkit2gtk3-javascriptcore
4−}:
5−mkDerivation {
6− pname = "jsaddle-webkit2gtk";
7− version = "0.9.4.0";
8− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
9− libraryHaskellDepends = [
10− aeson base bytestring directory gi-gio gi-glib gi-gtk
11− gi-javascriptcore gi-webkit2 haskell-gi-base jsaddle text unix
12− webkit2gtk3-javascriptcore
13− ];
14− description = "Interface for JavaScript that works with GHCJS and GHC";
15− license = stdenv.lib.licenses.mit;
16−}
jsaddle-webkit2gtk/jsaddle-webkit2gtk.cabal+4−4
@@ -1,5 +1,5 @@
1name: jsaddle-webkit2gtk
1name: jsaddle-webkit2gtk
2−version: 0.9.4.0
2+version: 0.9.8.0
3cabal-version: >=1.10
3cabal-version: >=1.10
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
@@ -26,7 +26,7 @@ library
26 base <5
26 base <5
27 if !impl(ghcjs -any)
27 if !impl(ghcjs -any)
28 build-depends:
28 build-depends:
29− aeson >=0.8.0.2 && <1.3,
29+ aeson >=0.8.0.2 && <1.6,
30 base <5,
30 base <5,
31 bytestring >=0.10.6.0 && <0.11,
31 bytestring >=0.10.6.0 && <0.11,
32 directory >=1.0.0.2 && <1.4,
32 directory >=1.0.0.2 && <1.4,
@@ -35,8 +35,8 @@ library
35 gi-gtk >=3.0.17 && <3.1,
35 gi-gtk >=3.0.17 && <3.1,
36 gi-webkit2 >=4.0.14 && <4.1,
36 gi-webkit2 >=4.0.14 && <4.1,
37 gi-javascriptcore >=4.0.14 && <4.1,
37 gi-javascriptcore >=4.0.14 && <4.1,
38− haskell-gi-base >=0.20 && <0.22,
38+ haskell-gi-base >=0.20 && <0.26,
39− haskell-gi-overloading ==0.0.*,
39+ haskell-gi-overloading >=0.0 && < 2.0,
40 jsaddle >=0.9.4.0 && <0.10,
40 jsaddle >=0.9.4.0 && <0.10,
41 text >=1.2.1.3 && <1.3,
41 text >=1.2.1.3 && <1.3,
42 webkit2gtk3-javascriptcore >=0.14.0.0 && <0.15
42 webkit2gtk3-javascriptcore >=0.14.0.0 && <0.15
jsaddle-webkit2gtk/src/Language/Javascript/JSaddle/WebKitGTK.hs+15−36
@@ -43,29 +43,24 @@ import Data.Monoid ((<>))
43import Data.ByteString.Lazy (toStrict, fromStrict)
43import Data.ByteString.Lazy (toStrict, fromStrict)
44import qualified Data.ByteString.Lazy as LB (ByteString)
44import qualified Data.ByteString.Lazy as LB (ByteString)
45import Data.Aeson (encode, decode)
45import Data.Aeson (encode, decode)
46−import Data.Text (Text)
47import qualified Data.Text as T (pack)
46import qualified Data.Text as T (pack)
48−import Data.Text.Foreign (fromPtr)
49import Data.Text.Encoding (decodeUtf8, encodeUtf8)
47import Data.Text.Encoding (decodeUtf8, encodeUtf8)
50
48
51−import Foreign.Ptr (castPtr, nullPtr)
52−
53import Data.GI.Base.BasicTypes (GObject)
49import Data.GI.Base.BasicTypes (GObject)
54import Data.GI.Base.Signals
50import Data.GI.Base.Signals
55 (connectSignalFunPtr, SignalConnectMode(..), SignalConnectMode,
51 (connectSignalFunPtr, SignalConnectMode(..), SignalConnectMode,
56 SignalHandlerId)
52 SignalHandlerId)
57−import Data.GI.Base.ManagedPtr (withManagedPtr)
58
53
59import GI.GLib (timeoutAdd, idleAdd, pattern PRIORITY_HIGH, pattern PRIORITY_DEFAULT)
54import GI.GLib (timeoutAdd, idleAdd, pattern PRIORITY_HIGH, pattern PRIORITY_DEFAULT)
60import qualified GI.Gtk as Gtk (main, init)
55import qualified GI.Gtk as Gtk (main, init)
61import GI.Gtk
56import GI.Gtk
62 (windowSetPosition, windowSetDefaultSize, windowNew,
57 (windowSetPosition, windowSetDefaultSize, windowNew,
63− scrolledWindowNew, noAdjustment, containerAdd,
58+ scrolledWindowNew, Adjustment, containerAdd,
64 WindowType(..), WindowPosition(..), widgetDestroy,
59 WindowType(..), WindowPosition(..), widgetDestroy,
65 widgetGetToplevel, widgetShowAll, onWidgetDestroy,
60 widgetGetToplevel, widgetShowAll, onWidgetDestroy,
66 mainQuit)
61 mainQuit)
67−import GI.Gio (noCancellable)
62+import GI.Gio (Cancellable)
68−import GI.JavaScriptCore (Value(..), GlobalContext(..))
63+import GI.JavaScriptCore (valueToString)
69import GI.WebKit2
64import GI.WebKit2
70 (scriptDialogPromptSetText, scriptDialogPromptGetDefaultText,
65 (scriptDialogPromptSetText, scriptDialogPromptGetDefaultText,
71 scriptDialogGetMessage, scriptDialogGetDialogType,
66 scriptDialogGetMessage, scriptDialogGetDialogType,
@@ -74,7 +69,7 @@ import GI.WebKit2
74 setSettingsEnableJavascript, webViewNewWithUserContentManager,
69 setSettingsEnableJavascript, webViewNewWithUserContentManager,
75 userContentManagerNew,
70 userContentManagerNew,
76 userContentManagerRegisterScriptMessageHandler,
71 userContentManagerRegisterScriptMessageHandler,
77− javascriptResultGetValue, javascriptResultGetGlobalContext,
72+ javascriptResultGetJsValue,
78 webViewGetUserContentManager,
73 webViewGetUserContentManager,
79 mk_UserContentManagerScriptMessageReceivedCallback,
74 mk_UserContentManagerScriptMessageReceivedCallback,
80 wrap_UserContentManagerScriptMessageReceivedCallback,
75 wrap_UserContentManagerScriptMessageReceivedCallback,
@@ -83,17 +78,16 @@ import GI.WebKit2
83 onWebViewLoadChanged, setSettingsEnableDeveloperExtras,
78 onWebViewLoadChanged, setSettingsEnableDeveloperExtras,
84 webViewSetSettings, webViewGetSettings, ScriptDialogType(..))
79 webViewSetSettings, webViewGetSettings, ScriptDialogType(..))
85
80
86−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSBase
87− (JSValueRef, JSContextRef)
88−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSStringRef
89− (jsstringgetcharactersptr, jsstringgetlength, jsstringrelease)
90−import Graphics.UI.Gtk.WebKit.JavaScriptCore.JSValueRef
91− (jsvaluetostringcopy)
92−
93import Language.Javascript.JSaddle (JSM, Results, Batch)
81import Language.Javascript.JSaddle (JSM, Results, Batch)
94import Language.Javascript.JSaddle.Run (runJavaScript)
82import Language.Javascript.JSaddle.Run (runJavaScript)
95import Language.Javascript.JSaddle.Run.Files (initState, runBatch, ghcjsHelpers)
83import Language.Javascript.JSaddle.Run.Files (initState, runBatch, ghcjsHelpers)
96
84
85+noAdjustment :: Maybe Adjustment
86+noAdjustment = Nothing
87+
88+noCancellable :: Maybe Cancellable
89+noCancellable = Nothing
90+
97quitWebView :: WebView -> IO ()
91quitWebView :: WebView -> IO ()
98quitWebView wv = postGUIAsync $ do w <- widgetGetToplevel wv --TODO: Shouldn't this be postGUISync?
92quitWebView wv = postGUIAsync $ do w <- widgetGetToplevel wv --TODO: Shouldn't this be postGUISync?
99 widgetDestroy w
93 widgetDestroy w
@@ -109,21 +103,6 @@ postGUIAsync :: IO () -> IO ()
109postGUIAsync action =
103postGUIAsync action =
110 void . idleAdd PRIORITY_DEFAULT $ action >> return False
104 void . idleAdd PRIORITY_DEFAULT $ action >> return False
111
105
112−withJSContextRef :: GlobalContext -> (JSContextRef -> IO a) -> IO a
113−withJSContextRef (GlobalContext ctx) f = withManagedPtr ctx (f . castPtr)
114−
115−withJSValueRef :: Value -> (JSValueRef -> IO a) -> IO a
116−withJSValueRef (Value ptr) f = withManagedPtr ptr (f . castPtr)
117−
118−valueToText :: JSContextRef -> JSValueRef -> IO Text
119−valueToText ctxRef s = do
120− jsstring <- jsvaluetostringcopy ctxRef s nullPtr
121− l <- jsstringgetlength jsstring
122− p <- jsstringgetcharactersptr jsstring
123− result <- fromPtr (castPtr p) (fromIntegral l)
124− jsstringrelease jsstring
125− return result
126−
127run :: JSM () -> IO ()
106run :: JSM () -> IO ()
128run main = do
107run main = do
129 _ <- Gtk.init Nothing
108 _ <- Gtk.init Nothing
@@ -172,16 +151,16 @@ connectUserContentManagerScriptMessageReceived obj cb after = liftIO $ do
172 let cb' = wrap_UserContentManagerScriptMessageReceivedCallback cb
151 let cb' = wrap_UserContentManagerScriptMessageReceivedCallback cb
173 cb'' <- mk_UserContentManagerScriptMessageReceivedCallback cb'
152 cb'' <- mk_UserContentManagerScriptMessageReceivedCallback cb'
174 connectSignalFunPtr obj "script-message-received::jsaddle" cb'' after
153 connectSignalFunPtr obj "script-message-received::jsaddle" cb'' after
154+#if MIN_VERSION_haskell_gi_base(0,23,0)
155+ Nothing
156+#endif
175
157
176addJSaddleHandler :: WebView -> (Results -> IO ()) -> (Results -> IO Batch) -> IO ()
158addJSaddleHandler :: WebView -> (Results -> IO ()) -> (Results -> IO Batch) -> IO ()
177addJSaddleHandler webView processResult syncResults = do
159addJSaddleHandler webView processResult syncResults = do
178 manager <- webViewGetUserContentManager webView
160 manager <- webViewGetUserContentManager webView
179 _ <- onUserContentManagerScriptMessageReceived manager $ \result -> do
161 _ <- onUserContentManagerScriptMessageReceived manager $ \result -> do
180− ctx <- javascriptResultGetGlobalContext result
162+ arg <- javascriptResultGetJsValue result
181− arg <- javascriptResultGetValue result
163+ bs <- encodeUtf8 <$> valueToString arg
182− bs <- withJSContextRef ctx $ \ctxRef ->
183− withJSValueRef arg $ \argRef ->
184− encodeUtf8 <$> valueToText ctxRef argRef
185 mapM_ processResult (decode (fromStrict bs))
164 mapM_ processResult (decode (fromStrict bs))
186 _ <- onWebViewScriptDialog webView $ \dialog ->
165 _ <- onWebViewScriptDialog webView $ \dialog ->
187 scriptDialogGetDialogType dialog >>= \case
166 scriptDialogGetDialogType dialog >>= \case
jsaddle-webkitgtk/default.nixdeleted−16
@@ -1,16 +0,0 @@
1−{ mkDerivation, aeson, base, bytestring, directory, gi-glib, gi-gtk
2−, gi-javascriptcore, gi-webkit, haskell-gi-base, jsaddle, stdenv
3−, text, unix, webkitgtk3-javascriptcore
4−}:
5−mkDerivation {
6− pname = "jsaddle-webkitgtk";
7− version = "0.9.0.0";
8− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
9− libraryHaskellDepends = [
10− aeson base bytestring directory gi-glib gi-gtk gi-javascriptcore
11− gi-webkit haskell-gi-base jsaddle text unix
12− webkitgtk3-javascriptcore
13− ];
14− description = "Interface for JavaScript that works with GHCJS and GHC";
15− license = stdenv.lib.licenses.mit;
16−}
jsaddle-wkwebview/cbits-cocoa/AppDelegate.m+57−2
@@ -2,6 +2,9 @@
2#import <Cocoa/Cocoa.h>
2#import <Cocoa/Cocoa.h>
3#import <WebKit/WebKit.h>
3#import <WebKit/WebKit.h>
4
4
5+extern void callIO(HsStablePtr);
6+extern bool callWithCStringReturningBool(const char * _Nonnull, HsStablePtr);
7+extern void callWithCString(const char * _Nonnull, HsStablePtr);
5extern void callWithWebView(WKWebView *, HsStablePtr);
8extern void callWithWebView(WKWebView *, HsStablePtr);
6
9
7@interface AppDelegate : NSObject <NSApplicationDelegate>
10@interface AppDelegate : NSObject <NSApplicationDelegate>
@@ -11,6 +14,12 @@ extern void callWithWebView(WKWebView *, HsStablePtr);
11- (instancetype)initApp:(HsStablePtr)handler progName:(NSString *)progName;
14- (instancetype)initApp:(HsStablePtr)handler progName:(NSString *)progName;
12@end
15@end
13
16
17+HsStablePtr global_willFinishLaunchingWithOptions = 0;
18+HsStablePtr global_didFinishLaunchingWithOptions = 0;
19+HsStablePtr global_applicationUniversalLink = 0;
20+HsStablePtr global_applicationOpenFile = 0;
21+uint64_t global_developerExtrasEnabled = 1;
22+
14@implementation AppDelegate
23@implementation AppDelegate
15
24
16- (void)applicationWillTerminate:(NSNotification *)aNotification {
25- (void)applicationWillTerminate:(NSNotification *)aNotification {
@@ -31,18 +40,39 @@ extern void callWithWebView(WKWebView *, HsStablePtr);
31 return self;
40 return self;
32}
41}
33
42
43+-(BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
44+ bool b = callWithCStringReturningBool([filename UTF8String], global_applicationOpenFile);
45+ return b ? YES : NO;
46+}
47+
34-(void)applicationWillFinishLaunching:(NSNotification *)notification {
48-(void)applicationWillFinishLaunching:(NSNotification *)notification {
35 WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
49 WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
50+ if (global_developerExtrasEnabled) {
36− [theConfiguration.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
51+ [theConfiguration.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
52+ }
37 WKWebView *webView = [[WKWebView alloc] initWithFrame: [_window.contentView frame] configuration:theConfiguration];
53 WKWebView *webView = [[WKWebView alloc] initWithFrame: [_window.contentView frame] configuration:theConfiguration];
38 [_window setContentView:webView];
54 [_window setContentView:webView];
39 callWithWebView(webView, _handler);
55 callWithWebView(webView, _handler);
56+ callIO(global_willFinishLaunchingWithOptions);
57+ // Listen to URL events
58+ NSAppleEventManager *manager = [NSAppleEventManager sharedAppleEventManager];
59+ [manager
60+ setEventHandler:self
61+ andSelector:@selector(applicationUniversalLink:)
62+ forEventClass:kInternetEventClass
63+ andEventID:kAEGetURL];
64+}
65+
66+- (void)applicationUniversalLink:(NSAppleEventDescriptor *)event {
67+ NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
68+ callWithCString([url UTF8String], global_applicationUniversalLink);
40}
69}
41
70
42-(void)applicationDidFinishLaunching:(NSNotification *)notification {
71-(void)applicationDidFinishLaunching:(NSNotification *)notification {
43 [_window orderFrontRegardless];
72 [_window orderFrontRegardless];
44 [_window center];
73 [_window center];
45 [NSApp activateIgnoringOtherApps:YES];
74 [NSApp activateIgnoringOtherApps:YES];
75+ callIO(global_didFinishLaunchingWithOptions);
46}
76}
47
77
48-(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app {
78-(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app {
@@ -51,8 +81,33 @@ extern void callWithWebView(WKWebView *, HsStablePtr);
51
81
52@end
82@end
53
83
54−void runInWKWebView(HsStablePtr handler, const char * _Nonnull progName) {
84+void runInWKWebView(HsStablePtr handler,
85+ const char * _Nonnull progName,
86+ HsStablePtr hs_willFinishLaunchingWithOptions,
87+ HsStablePtr hs_didFinishLaunchingWithOptions,
88+ HsStablePtr hs_applicationDidBecomeActive,
89+ HsStablePtr hs_applicationWillResignActive,
90+ HsStablePtr hs_applicationDidEnterBackground,
91+ HsStablePtr hs_applicationWillEnterForeground,
92+ HsStablePtr hs_applicationWillTerminate,
93+ HsStablePtr hs_applicationSignificantTimeChange,
94+ HsStablePtr hs_applicationUniversalLink,
95+ const uint64_t hs_requestAuthorizationWithOptions,
96+ const uint64_t hs_requestAuthorizationOptionBadge,
97+ const uint64_t hs_requestAuthorizationOptionSound,
98+ const uint64_t hs_requestAuthorizationOptionAlert,
99+ const uint64_t hs_requestAuthorizationOptionCarPlay,
100+ const uint64_t hs_registerForRemoteNotifications,
101+ HsStablePtr hs_didRegisterForRemoteNotificationsWithDeviceToken,
102+ HsStablePtr hs_didFailToRegisterForRemoteNotificationsWithError,
103+ const uint64_t hs_developerExtrasEnabled,
104+ HsStablePtr hs_applicationOpenFile) {
55 @autoreleasepool {
105 @autoreleasepool {
106+ global_willFinishLaunchingWithOptions = hs_willFinishLaunchingWithOptions;
107+ global_didFinishLaunchingWithOptions = hs_didFinishLaunchingWithOptions;
108+ global_applicationUniversalLink = hs_applicationUniversalLink;
109+ global_applicationOpenFile = hs_applicationOpenFile;
110+ global_developerExtrasEnabled = hs_developerExtrasEnabled;
56 NSApplication *application = [NSApplication sharedApplication];
111 NSApplication *application = [NSApplication sharedApplication];
57 AppDelegate *appDelegate = [[AppDelegate alloc] initApp:handler progName:[NSString stringWithCString:progName encoding:NSUTF8StringEncoding]];
112 AppDelegate *appDelegate = [[AppDelegate alloc] initApp:handler progName:[NSString stringWithCString:progName encoding:NSUTF8StringEncoding]];
58 [application setDelegate:appDelegate];
113 [application setDelegate:appDelegate];
jsaddle-wkwebview/cbits-uikit/AppDelegate.m+14−1
@@ -5,6 +5,7 @@
5
5
6extern void callIO(HsStablePtr);
6extern void callIO(HsStablePtr);
7extern void callWithCString(const char * _Nonnull, HsStablePtr);
7extern void callWithCString(const char * _Nonnull, HsStablePtr);
8+extern void callWithCIntCString(int n, const char * _Nonnull, HsStablePtr);
8
9
9@interface AppDelegate ()
10@interface AppDelegate ()
10
11
@@ -20,6 +21,7 @@ HsStablePtr global_applicationWillEnterForeground = 0;
20HsStablePtr global_applicationWillTerminate = 0;
21HsStablePtr global_applicationWillTerminate = 0;
21HsStablePtr global_applicationSignificantTimeChange = 0;
22HsStablePtr global_applicationSignificantTimeChange = 0;
22HsStablePtr global_applicationUniversalLink = 0;
23HsStablePtr global_applicationUniversalLink = 0;
24+HsStablePtr global_applicationDidReceiveRemoteNotification = 0;
23uint64_t global_requestAuthorizationWithOptions = 0;
25uint64_t global_requestAuthorizationWithOptions = 0;
24uint64_t global_requestAuthorizationOptionBadge = 0;
26uint64_t global_requestAuthorizationOptionBadge = 0;
25uint64_t global_requestAuthorizationOptionSound = 0;
27uint64_t global_requestAuthorizationOptionSound = 0;
@@ -115,6 +117,14 @@ HsStablePtr global_didFailToRegisterForRemoteNotificationsWithError = 0;
115 if ([userInfo valueForKeyPath:@"aps.badge"] != nil) {
117 if ([userInfo valueForKeyPath:@"aps.badge"] != nil) {
116 [UIApplication sharedApplication].applicationIconBadgeNumber=[[[userInfo objectForKey:@"aps"] objectForKey:@"badge"] intValue];
118 [UIApplication sharedApplication].applicationIconBadgeNumber=[[[userInfo objectForKey:@"aps"] objectForKey:@"badge"] intValue];
117 }
119 }
120+ NSError *error;
121+ NSData *jsonData = [NSJSONSerialization dataWithJSONObject:userInfo options:0 error:&error];
122+ if (jsonData) {
123+ NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
124+ callWithCIntCString((int) application.applicationState, [jsonString UTF8String], global_applicationDidReceiveRemoteNotification);
125+ } else {
126+ NSLog(@"jsaddle-wkwebview didReceiveRemoteNotification handler: error while serialising push notification as JSON");
127+ }
118 completionHandler(UIBackgroundFetchResultNewData);
128 completionHandler(UIBackgroundFetchResultNewData);
119}
129}
120
130
@@ -152,6 +162,7 @@ void runInWKWebView(HsStablePtr handler,
152 HsStablePtr hs_applicationWillTerminate,
162 HsStablePtr hs_applicationWillTerminate,
153 HsStablePtr hs_applicationSignificantTimeChange,
163 HsStablePtr hs_applicationSignificantTimeChange,
154 HsStablePtr hs_applicationUniversalLink,
164 HsStablePtr hs_applicationUniversalLink,
165+ HsStablePtr hs_applicationDidReceiveRemoteNotification,
155 const uint64_t hs_requestAuthorizationWithOptions,
166 const uint64_t hs_requestAuthorizationWithOptions,
156 const uint64_t hs_requestAuthorizationOptionBadge,
167 const uint64_t hs_requestAuthorizationOptionBadge,
157 const uint64_t hs_requestAuthorizationOptionSound,
168 const uint64_t hs_requestAuthorizationOptionSound,
@@ -159,7 +170,8 @@ void runInWKWebView(HsStablePtr handler,
159 const uint64_t hs_requestAuthorizationOptionCarPlay,
170 const uint64_t hs_requestAuthorizationOptionCarPlay,
160 const uint64_t hs_registerForRemoteNotifications,
171 const uint64_t hs_registerForRemoteNotifications,
161 HsStablePtr hs_didRegisterForRemoteNotificationsWithDeviceToken,
172 HsStablePtr hs_didRegisterForRemoteNotificationsWithDeviceToken,
162− HsStablePtr hs_didFailToRegisterForRemoteNotificationsWithError) {
173+ HsStablePtr hs_didFailToRegisterForRemoteNotificationsWithError,
174+ const uint64_t hs_developerExtrasEnabled) {
163 @autoreleasepool {
175 @autoreleasepool {
164 globalHandler = handler;
176 globalHandler = handler;
165 global_willFinishLaunchingWithOptions = hs_willFinishLaunchingWithOptions;
177 global_willFinishLaunchingWithOptions = hs_willFinishLaunchingWithOptions;
@@ -171,6 +183,7 @@ void runInWKWebView(HsStablePtr handler,
171 global_applicationWillTerminate = hs_applicationWillTerminate;
183 global_applicationWillTerminate = hs_applicationWillTerminate;
172 global_applicationSignificantTimeChange = hs_applicationSignificantTimeChange;
184 global_applicationSignificantTimeChange = hs_applicationSignificantTimeChange;
173 global_applicationUniversalLink = hs_applicationUniversalLink;
185 global_applicationUniversalLink = hs_applicationUniversalLink;
186+ global_applicationDidReceiveRemoteNotification = hs_applicationDidReceiveRemoteNotification;
174 global_requestAuthorizationWithOptions = hs_requestAuthorizationWithOptions;
187 global_requestAuthorizationWithOptions = hs_requestAuthorizationWithOptions;
175 global_requestAuthorizationOptionBadge = hs_requestAuthorizationOptionBadge;
188 global_requestAuthorizationOptionBadge = hs_requestAuthorizationOptionBadge;
176 global_requestAuthorizationOptionSound = hs_requestAuthorizationOptionSound;
189 global_requestAuthorizationOptionSound = hs_requestAuthorizationOptionSound;
jsaddle-wkwebview/default.nix+14−30
@@ -1,30 +1,14 @@
1−{ mkDerivation, stdenv, aeson, base, bytestring, jsaddle, data-default
1+{ filterSource ? (x: x) }:
2−, buildPackages, hostPlatform
2+self: super:
3−}:
3+let
4−
4+ pkgs = self.callPackage ({pkgs}: pkgs) {};
5−mkDerivation {
5+ inherit (pkgs) lib;
6− pname = "jsaddle-wkwebview";
6+in
7− version = "0.9.4.0";
7+with pkgs.haskell.lib;
8− src = ./.;
8+overrideCabal (self.callCabal2nix "jsaddle-wkwebview" (filterSource ./.) {}) (drv: {
9− libraryHaskellDepends = [ aeson base bytestring jsaddle data-default ];
9+ libraryFrameworkDepends = (drv.libraryFrameworkDepends or []) ++
10−
11− # HACK(matthewbauer): Can’t figure out why cf-private framework is
12− # not getting pulled in correctly. Has something
13− # to with how headers are looked up in xcode.
14− preBuild = stdenv.lib.optionalString (!hostPlatform.useiOSPrebuilt) ''
15− mkdir include
16− ln -s ${buildPackages.darwin.cf-private}/Library/Frameworks/CoreFoundation.framework/Headers include/CoreFoundation
17− export NIX_CFLAGS_COMPILE="-I$PWD/include $NIX_CFLAGS_COMPILE"
18− '';
19−
20− libraryFrameworkDepends =
21− stdenv.lib.optional (hostPlatform.useiOSPrebuilt)
10+ (if pkgs.stdenv.hostPlatform.useiOSPrebuilt then [
22− "${buildPackages.darwin.xcode}/Contents/Developer/Platforms/${hostPlatform.xcodePlatform}.platform/Developer/SDKs/${hostPlatform.xcodePlatform}.sdk/System"
11+ "${pkgs.buildPackages.darwin.xcode}/Contents/Developer/Platforms/${pkgs.stdenv.hostPlatform.xcodePlatform}.platform/Developer/SDKs/${pkgs.stdenv.hostPlatform.xcodePlatform}.sdk/System"
23− ++ stdenv.lib.optional (!hostPlatform.useiOSPrebuilt)
24− (with buildPackages.darwin; with apple_sdk.frameworks; [
12+ ] else (with pkgs.buildPackages.darwin.apple_sdk.frameworks; [ Cocoa WebKit ]));
25− Cocoa
13+ buildDepends = lib.optional (!pkgs.stdenv.hostPlatform.useiOSPrebuilt) [ pkgs.buildPackages.darwin.cf-private ];
26− WebKit
27− ]);
28− description = "Interface for JavaScript that works with GHCJS and GHC";
29− license = stdenv.lib.licenses.mit;
30−}
14+})
jsaddle-wkwebview/jsaddle-wkwebview.cabal+5−3
@@ -1,5 +1,5 @@
1name: jsaddle-wkwebview
1name: jsaddle-wkwebview
2−version: 0.9.4.0
2+version: 0.9.8.0
3cabal-version: >=1.10
3cabal-version: >=1.10
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
@@ -29,13 +29,15 @@ library
29 base <5
29 base <5
30 default-language: Haskell2010
30 default-language: Haskell2010
31 hs-source-dirs: src
31 hs-source-dirs: src
32− frameworks: Foundation, WebKit
33 ghc-options: -ferror-spans -Wall
32 ghc-options: -ferror-spans -Wall
33+ if os(linux)
34+ buildable: False
34 if impl(ghcjs)
35 if impl(ghcjs)
35 hs-source-dirs: src-ghcjs
36 hs-source-dirs: src-ghcjs
36 else
37 else
38+ frameworks: Foundation, WebKit
37 build-depends:
39 build-depends:
38− aeson >=0.8.0.2 && <1.3,
40+ aeson >=0.8.0.2 && <1.6,
39 bytestring >=0.10.6.0 && <0.11,
41 bytestring >=0.10.6.0 && <0.11,
40 directory,
42 directory,
41 jsaddle >= 0.9.4.0 && <0.10,
43 jsaddle >= 0.9.4.0 && <0.10,
jsaddle-wkwebview/src-ghc/Language/Javascript/JSaddle/WKWebView.hs+43
@@ -9,6 +9,7 @@ module Language.Javascript.JSaddle.WKWebView
9 , runHTMLWithBaseURL
9 , runHTMLWithBaseURL
10 , runFile
10 , runFile
11 , mainBundleResourcePath
11 , mainBundleResourcePath
12+ , ApplicationState (..)
12 , AppDelegateConfig (..)
13 , AppDelegateConfig (..)
13 , AppDelegateNotificationConfig (..)
14 , AppDelegateNotificationConfig (..)
14 , AuthorizationOption (..)
15 , AuthorizationOption (..)
@@ -24,6 +25,7 @@ import Language.Javascript.JSaddle.WKWebView.Internal
24 (jsaddleMain, jsaddleMainHTMLWithBaseURL, jsaddleMainFile, WKWebView(..), mainBundleResourcePath)
25 (jsaddleMain, jsaddleMainHTMLWithBaseURL, jsaddleMainFile, WKWebView(..), mainBundleResourcePath)
25import System.Environment (getProgName)
26import System.Environment (getProgName)
26import Foreign.C.String (CString, withCString)
27import Foreign.C.String (CString, withCString)
28+import Foreign.C.Types (CBool, CInt)
27import Foreign.StablePtr (StablePtr, newStablePtr)
29import Foreign.StablePtr (StablePtr, newStablePtr)
28import Language.Javascript.JSaddle (JSM)
30import Language.Javascript.JSaddle (JSM)
29
31
@@ -39,6 +41,7 @@ foreign import ccall runInWKWebView
39 -> StablePtr (IO ()) -- applicationWillTerminate
41 -> StablePtr (IO ()) -- applicationWillTerminate
40 -> StablePtr (IO ()) -- applicationSignificantTimeChange
42 -> StablePtr (IO ()) -- applicationSignificantTimeChange
41 -> StablePtr (CString -> IO ()) -- applicationUniversalLink
43 -> StablePtr (CString -> IO ()) -- applicationUniversalLink
44+ -> StablePtr (CInt -> CString -> IO ()) -- applicationDidReceiveRemoteNotification
42 -> Word64 -- whether to run requestAuthorizationWithOptions
45 -> Word64 -- whether to run requestAuthorizationWithOptions
43 -> Word64 -- Ask for Badge authorization
46 -> Word64 -- Ask for Badge authorization
44 -> Word64 -- Ask for Sound authorization
47 -> Word64 -- Ask for Sound authorization
@@ -47,6 +50,8 @@ foreign import ccall runInWKWebView
47 -> Word64 -- registerForRemoteNotifications
50 -> Word64 -- registerForRemoteNotifications
48 -> StablePtr (CString -> IO ()) -- didRegisterForRemoteNotificationsWithDeviceToken
51 -> StablePtr (CString -> IO ()) -- didRegisterForRemoteNotificationsWithDeviceToken
49 -> StablePtr (CString -> IO ()) -- didFailToRegisterForRemoteNotificationsWithError
52 -> StablePtr (CString -> IO ()) -- didFailToRegisterForRemoteNotificationsWithError
53+ -> Word64 -- developerExtrasEnabled
54+ -> StablePtr (CString -> IO CBool) -- applicationOpenFile
50 -> IO ()
55 -> IO ()
51
56
52data AppDelegateConfig = AppDelegateConfig
57data AppDelegateConfig = AppDelegateConfig
@@ -59,7 +64,25 @@ data AppDelegateConfig = AppDelegateConfig
59 , _appDelegateConfig_applicationWillTerminate :: IO ()
64 , _appDelegateConfig_applicationWillTerminate :: IO ()
60 , _appDelegateConfig_applicationSignificantTimeChange :: IO ()
65 , _appDelegateConfig_applicationSignificantTimeChange :: IO ()
61 , _appDelegateConfig_applicationUniversalLink :: CString -> IO ()
66 , _appDelegateConfig_applicationUniversalLink :: CString -> IO ()
67+ -- ^ Called when the app is launched from a URL. 'CString' contains the URL.
68+ --
69+ -- The Core Foundation plist key CFBundleURLTypes controls which URL schemes
70+ -- the app should respond to.
71+ , _appDelegateConfig_applicationDidReceiveRemoteNotification :: ApplicationState -> CString -> IO ()
72+ -- ^ Called when the application receives a remote notification.
73+ -- 'ApplicationState' is the current state of the app.
74+ -- The 'CString' JSON-encoded user info contained in the notification.
75+ -- For more information see https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623117-application?language=objc
62 , _appDelegateConfig_appDelegateNotificationConfig :: AppDelegateNotificationConfig
76 , _appDelegateConfig_appDelegateNotificationConfig :: AppDelegateNotificationConfig
77+ , _appDelegateConfig_developerExtrasEnabled :: Bool
78+ -- ^ Allow devtools in the app. Defaults to 'True'
79+ , _appDelegateConfig_applicationOpenFile :: CString -> IO Bool
80+ -- ^ Called when the app is launched by opening a file. 'CString' contains
81+ -- the file path. Return value is 'True' if the file was successfully
82+ -- opened. Defaults to ignoring the file and returning 'False'.
83+ --
84+ -- The Core Foundation plist key CFBundleDocumentTypes controls which file
85+ -- types should be associated with the app.
63 }
86 }
64
87
65instance Default AppDelegateConfig where
88instance Default AppDelegateConfig where
@@ -73,7 +96,10 @@ instance Default AppDelegateConfig where
73 , _appDelegateConfig_applicationWillTerminate = return ()
96 , _appDelegateConfig_applicationWillTerminate = return ()
74 , _appDelegateConfig_applicationSignificantTimeChange = return ()
97 , _appDelegateConfig_applicationSignificantTimeChange = return ()
75 , _appDelegateConfig_applicationUniversalLink = \_ -> return ()
98 , _appDelegateConfig_applicationUniversalLink = \_ -> return ()
99+ , _appDelegateConfig_applicationDidReceiveRemoteNotification = \_ _ -> return ()
76 , _appDelegateConfig_appDelegateNotificationConfig = def
100 , _appDelegateConfig_appDelegateNotificationConfig = def
101+ , _appDelegateConfig_developerExtrasEnabled = True
102+ , _appDelegateConfig_applicationOpenFile = \_ -> return False
77 }
103 }
78
104
79data AuthorizationOption = AuthorizationOption_Badge
105data AuthorizationOption = AuthorizationOption_Badge
@@ -82,6 +108,12 @@ data AuthorizationOption = AuthorizationOption_Badge
82 | AuthorizationOption_CarPlay
108 | AuthorizationOption_CarPlay
83 deriving (Show, Read, Eq, Ord)
109 deriving (Show, Read, Eq, Ord)
84
110
111+data ApplicationState = ApplicationState_Active
112+ | ApplicationState_Inactive
113+ | ApplicationState_Background
114+ | ApplicationState_Unknown CInt
115+ deriving (Show, Read, Eq, Ord)
116+
85data AppDelegateNotificationConfig = AppDelegateNotificationConfig
117data AppDelegateNotificationConfig = AppDelegateNotificationConfig
86 { _appDelegateNotificationConfig_requestAuthorizationWithOptions :: Maybe (Set AuthorizationOption)
118 { _appDelegateNotificationConfig_requestAuthorizationWithOptions :: Maybe (Set AuthorizationOption)
87 , _appDelegateNotificationConfig_registerForRemoteNotifications :: Bool
119 , _appDelegateNotificationConfig_registerForRemoteNotifications :: Bool
@@ -144,6 +176,14 @@ run' cfg main = do
144 applicationWillTerminate <- newStablePtr $ _appDelegateConfig_applicationWillTerminate cfg
176 applicationWillTerminate <- newStablePtr $ _appDelegateConfig_applicationWillTerminate cfg
145 applicationSignificantTimeChange <- newStablePtr $ _appDelegateConfig_applicationSignificantTimeChange cfg
177 applicationSignificantTimeChange <- newStablePtr $ _appDelegateConfig_applicationSignificantTimeChange cfg
146 applicationUniversalLink <- newStablePtr $ _appDelegateConfig_applicationUniversalLink cfg
178 applicationUniversalLink <- newStablePtr $ _appDelegateConfig_applicationUniversalLink cfg
179+ applicationDidReceiveRemoteNotification <- newStablePtr $ \n s -> do
180+ let appState = case n of
181+ 0 -> ApplicationState_Active
182+ 1 -> ApplicationState_Inactive
183+ 2 -> ApplicationState_Background
184+ _ -> ApplicationState_Unknown n
185+ _appDelegateConfig_applicationDidReceiveRemoteNotification cfg appState s
186+ applicationOpenFile <- newStablePtr $ fmap fromBool . _appDelegateConfig_applicationOpenFile cfg
147
187
148 -- AppDelegate notification configuration
188 -- AppDelegate notification configuration
149 let ncfg = _appDelegateConfig_appDelegateNotificationConfig cfg
189 let ncfg = _appDelegateConfig_appDelegateNotificationConfig cfg
@@ -166,6 +206,7 @@ run' cfg main = do
166 applicationWillTerminate
206 applicationWillTerminate
167 applicationSignificantTimeChange
207 applicationSignificantTimeChange
168 applicationUniversalLink
208 applicationUniversalLink
209+ applicationDidReceiveRemoteNotification
169 (fromBool requestAuthorizationWithOptions)
210 (fromBool requestAuthorizationWithOptions)
170 (fromBool $ Set.member AuthorizationOption_Badge authorizationOptions)
211 (fromBool $ Set.member AuthorizationOption_Badge authorizationOptions)
171 (fromBool $ Set.member AuthorizationOption_Sound authorizationOptions)
212 (fromBool $ Set.member AuthorizationOption_Sound authorizationOptions)
@@ -174,3 +215,5 @@ run' cfg main = do
174 (fromBool registerForRemoteNotifications)
215 (fromBool registerForRemoteNotifications)
175 didRegisterForRemoteNotificationsWithDeviceToken
216 didRegisterForRemoteNotificationsWithDeviceToken
176 didFailToRegisterForRemoteNotificationsWithError
217 didFailToRegisterForRemoteNotificationsWithError
218+ (fromBool $ _appDelegateConfig_developerExtrasEnabled cfg)
219+ applicationOpenFile
jsaddle-wkwebview/src/Language/Javascript/JSaddle/WKWebView/Internal.hs+13
@@ -20,6 +20,7 @@ import qualified Data.Text as T (pack)
20import Data.Text.Encoding (encodeUtf8)
20import Data.Text.Encoding (encodeUtf8)
21
21
22import Foreign.C.String (CString)
22import Foreign.C.String (CString)
23+import Foreign.C.Types (CBool(..), CInt(..))
23import Foreign.Ptr (Ptr, nullPtr)
24import Foreign.Ptr (Ptr, nullPtr)
24import Foreign.StablePtr (StablePtr, newStablePtr, deRefStablePtr)
25import Foreign.StablePtr (StablePtr, newStablePtr, deRefStablePtr)
25
26
@@ -36,7 +37,9 @@ foreign export ccall jsaddleStart :: StablePtr (IO ()) -> IO ()
36foreign export ccall jsaddleResult :: StablePtr (Results -> IO ()) -> CString -> IO ()
37foreign export ccall jsaddleResult :: StablePtr (Results -> IO ()) -> CString -> IO ()
37foreign export ccall jsaddleSyncResult :: StablePtr (Results -> IO Batch) -> JSaddleHandler -> CString -> IO ()
38foreign export ccall jsaddleSyncResult :: StablePtr (Results -> IO Batch) -> JSaddleHandler -> CString -> IO ()
38foreign export ccall callWithWebView :: WKWebView -> StablePtr (WKWebView -> IO ()) -> IO ()
39foreign export ccall callWithWebView :: WKWebView -> StablePtr (WKWebView -> IO ()) -> IO ()
40+foreign export ccall callWithCIntCString :: CInt -> CString -> StablePtr (CInt -> CString -> IO ()) -> IO ()
39foreign export ccall callWithCString :: CString -> StablePtr (CString -> IO ()) -> IO ()
41foreign export ccall callWithCString :: CString -> StablePtr (CString -> IO ()) -> IO ()
42+foreign export ccall callWithCStringReturningBool :: CString -> StablePtr (CString -> IO CBool) -> IO CBool
40foreign export ccall callIO :: StablePtr (IO ()) -> IO ()
43foreign export ccall callIO :: StablePtr (IO ()) -> IO ()
41foreign import ccall addJSaddleHandler :: WKWebView -> StablePtr (IO ()) -> StablePtr (Results -> IO ()) -> StablePtr (Results -> IO Batch) -> IO ()
44foreign import ccall addJSaddleHandler :: WKWebView -> StablePtr (IO ()) -> StablePtr (Results -> IO ()) -> StablePtr (Results -> IO Batch) -> IO ()
42foreign import ccall loadHTMLStringWithBaseURL :: WKWebView -> CString -> CString -> IO ()
45foreign import ccall loadHTMLStringWithBaseURL :: WKWebView -> CString -> CString -> IO ()
@@ -126,6 +129,16 @@ callWithCString c fptr = do
126 f <- deRefStablePtr fptr
129 f <- deRefStablePtr fptr
127 f c
130 f c
128
131
132+callWithCIntCString :: CInt -> CString -> StablePtr (CInt -> CString -> IO ()) -> IO ()
133+callWithCIntCString n s fptr = do
134+ f <- deRefStablePtr fptr
135+ f n s
136+
137+callWithCStringReturningBool :: CString -> StablePtr (CString -> IO CBool) -> IO CBool
138+callWithCStringReturningBool c fptr = do
139+ f <- deRefStablePtr fptr
140+ f c
141+
129callIO :: StablePtr (IO ()) -> IO ()
142callIO :: StablePtr (IO ()) -> IO ()
130callIO ptr = do
143callIO ptr = do
131 f <- deRefStablePtr ptr
144 f <- deRefStablePtr ptr
jsaddle/default.nixdeleted−23
@@ -1,23 +0,0 @@
1−{ mkDerivation, aeson, attoparsec, base, base64-bytestring
2−, bytestring, containers, deepseq, filepath, ghc-prim, http-types
3−, lens, primitive, process, random, ref-tf, scientific, stdenv, stm
4−, text, time, transformers, unordered-containers, unliftio-core
5−, vector, exceptions, ghcjs-base, ghcjs-prim, ghc
6−}:
7−mkDerivation {
8− pname = "jsaddle";
9− version = "0.9.4.0";
10− src = builtins.filterSource (path: type: !(builtins.elem (baseNameOf path) [ ".git" "dist" ])) ./.;
11− libraryHaskellDepends = [
12− aeson base base64-bytestring bytestring exceptions lens primitive
13− text transformers
14− ] ++ (if ghc.isGhcjs or false then [
15− ghcjs-base ghcjs-prim
16− ] else [
17− attoparsec containers deepseq filepath ghc-prim http-types process
18− random ref-tf scientific stm time unordered-containers vector
19− unliftio-core
20− ]);
21− description = "Interface for JavaScript that works with GHCJS and GHC";
22− license = stdenv.lib.licenses.mit;
23−}
jsaddle/jsaddle.cabal+13−12
@@ -1,5 +1,5 @@
1name: jsaddle
1name: jsaddle
2−version: 0.9.5.0
2+version: 0.9.8.0
3cabal-version: >=1.10
3cabal-version: >=1.10
4build-type: Simple
4build-type: Simple
5license: MIT
5license: MIT
@@ -10,7 +10,7 @@ description:
10 This package provides an EDSL for calling JavaScript that
10 This package provides an EDSL for calling JavaScript that
11 can be used both from GHCJS and GHC. When using GHC
11 can be used both from GHCJS and GHC. When using GHC
12 the application is run using Warp and WebSockets to
12 the application is run using Warp and WebSockets to
13− drive a small JavaScipt helper.
13+ drive a small JavaScript helper.
14category: Web, Javascript
14category: Web, Javascript
15author: Hamish Mackenzie
15author: Hamish Mackenzie
16
16
@@ -36,20 +36,20 @@ library
36 else
36 else
37 build-depends:
37 build-depends:
38 attoparsec >=0.11 && <0.14,
38 attoparsec >=0.11 && <0.14,
39− containers >=0.5.6.2 && <0.6,
39+ containers >=0.5.6.2 && <0.7,
40 deepseq >=1.3 && < 1.5,
40 deepseq >=1.3 && < 1.5,
41 filepath >=1.4.0.0 && <1.5,
41 filepath >=1.4.0.0 && <1.5,
42 ghc-prim,
42 ghc-prim,
43 http-types >=0.8.6 && <0.13,
43 http-types >=0.8.6 && <0.13,
44 process >=1.2.3.0 && <1.7,
44 process >=1.2.3.0 && <1.7,
45− random >= 1.1 && < 1.2,
45+ random >= 1.1 && < 1.3,
46 ref-tf >=0.4.0.1 && <0.5,
46 ref-tf >=0.4.0.1 && <0.5,
47 scientific >=0.3 && <0.4,
47 scientific >=0.3 && <0.4,
48− stm >=2.4.4 && <2.5,
48+ stm >=2.4.4 && <2.6,
49− time >=1.5.0.1 && <1.9,
49+ time >=1.5.0.1 && <1.11,
50 unordered-containers >=0.2 && <0.3,
50 unordered-containers >=0.2 && <0.3,
51 vector >=0.10 && <0.13,
51 vector >=0.10 && <0.13,
52− unliftio-core >=0.1 && < 0.2
52+ unliftio-core >=0.1 && < 0.3
53 exposed-modules:
53 exposed-modules:
54 Data.JSString
54 Data.JSString
55 Data.JSString.Internal
55 Data.JSString.Internal
@@ -107,13 +107,14 @@ library
107 Language.Javascript.JSaddle.Value
107 Language.Javascript.JSaddle.Value
108 Language.Javascript.JSaddle.Types
108 Language.Javascript.JSaddle.Types
109 build-depends:
109 build-depends:
110− aeson >=0.8.0.2 && <1.4,
110+ aeson >=0.11.3.0 && <1.6,
111− base <5,
111+ base >=4.9 && <5,
112+ base-compat >=0.9.0 && <0.12,
112− base64-bytestring >=1.0.0.1 && <1.1,
113+ base64-bytestring >=1.0.0.1 && <1.2,
113 bytestring >=0.10.6.0 && <0.11,
114 bytestring >=0.10.6.0 && <0.11,
114 exceptions >=0.8 && <0.11,
115 exceptions >=0.8 && <0.11,
115− lens >=3.8.5 && <4.17,
116+ lens >=3.8.5 && <5.1,
116− primitive >=0.6.1.0 && <0.7,
117+ primitive >=0.6.1.0 && <0.8,
117 text >=1.2.1.3 && <1.3,
118 text >=1.2.1.3 && <1.3,
118 transformers >=0.4.2.0 && <0.6
119 transformers >=0.4.2.0 && <0.6
119 default-language: Haskell2010
120 default-language: Haskell2010
jsaddle/src-ghc/JavaScript/Array.hs+2−2
@@ -48,7 +48,7 @@ import Language.Javascript.JSaddle.Types
48 (JSM, JSVal, SomeJSArray(..), JSArray,
48 (JSM, JSVal, SomeJSArray(..), JSArray,
49 MutableJSArray, GHCJSPure(..))
49 MutableJSArray, GHCJSPure(..))
50import Control.Lens.Operators ((^.))
50import Control.Lens.Operators ((^.))
51−import Language.Javascript.JSaddle.Object (js2, js0, (##), js1, js)
51+import Language.Javascript.JSaddle.Object (js2, js0, (<##), js1, js)
52import Language.Javascript.JSaddle.Value (valToNumber)
52import Language.Javascript.JSaddle.Value (valToNumber)
53import JavaScript.Array.Internal (create, fromList, fromListIO, toList, toListIO, index, read, push)
53import JavaScript.Array.Internal (create, fromList, fromListIO, toList, toListIO, index, read, push)
54
54
@@ -69,7 +69,7 @@ append (SomeJSArray x) (SomeJSArray y) = SomeJSArray <$> x ^. js1 "concat" y
69{-# INLINE append #-}
69{-# INLINE append #-}
70
70
71write :: Int -> JSVal -> MutableJSArray -> JSM ()
71write :: Int -> JSVal -> MutableJSArray -> JSM ()
72−write n e (SomeJSArray x) = void $ (x ## n) e
72+write n e (SomeJSArray x) = void $ (x <## n) e
73{-# INLINE write #-}
73{-# INLINE write #-}
74
74
75pop :: MutableJSArray -> JSM JSVal
75pop :: MutableJSArray -> JSM JSVal
jsaddle/src/Language/Javascript/JSaddle.hs+5−5
@@ -9,7 +9,7 @@
9-- | This package provides an EDSL for calling JavaScript that
9-- | This package provides an EDSL for calling JavaScript that
10-- can be used both from GHCJS and GHC. When using GHC
10-- can be used both from GHCJS and GHC. When using GHC
11-- the application is run using Warp and WebSockets to
11-- the application is run using Warp and WebSockets to
12−-- drive a small JavaScipt helper.
12+-- drive a small JavaScript helper.
13-----------------------------------------------------------------------------
13-----------------------------------------------------------------------------
14
14
15module Language.Javascript.JSaddle (
15module Language.Javascript.JSaddle (
@@ -35,10 +35,10 @@ module Language.Javascript.JSaddle (
35 --
35 --
36 -- Where it makes sense code examples are given in two forms. One
36 -- Where it makes sense code examples are given in two forms. One
37 -- that uses 'eval' to run a purely JavaScript version and one that
37 -- that uses 'eval' to run a purely JavaScript version and one that
38− -- uses more of the JSaddle EDSL feature being demonstated.
38+ -- uses more of the JSaddle EDSL feature being demonstrated.
39
39
40 -- * Calling Haskell from JavaScript
40 -- * Calling Haskell from JavaScript
41− -- | You can call back into haskell from JavaScript using 'fun' to
41+ -- | You can call back into Haskell from JavaScript using 'fun' to
42 -- convert a Haskell function in the JSM monad into a javascript
42 -- convert a Haskell function in the JSM monad into a javascript
43 -- value.
43 -- value.
44
44
@@ -52,8 +52,8 @@ module Language.Javascript.JSaddle (
52 -- and the server will run the Haskell code. The JSaddle parts will
52 -- and the server will run the Haskell code. The JSaddle parts will
53 -- be executed by sending commands back to the browser.
53 -- be executed by sending commands back to the browser.
54
54
55− -- Although the code JavaScript code is executed in the the strict order
55+ -- Although the JavaScript code is executed in the strict order
56− -- set out by the EDSL it done asynchonously to the Haskell code.
56+ -- set out by the EDSL it is done asynchronously to the Haskell code.
57 -- This improves the performance by reducing the number of round trips
57 -- This improves the performance by reducing the number of round trips
58 -- needed between the Haskell and JavaScript code.
58 -- needed between the Haskell and JavaScript code.
59
59
jsaddle/src/Language/Javascript/JSaddle/Evaluate.hs+1−1
@@ -50,7 +50,7 @@ eval :: (ToJSString script)
50 -> JSM JSVal
50 -> JSM JSVal
51#ifdef ghcjs_HOST_OS
51#ifdef ghcjs_HOST_OS
52eval script = liftIO $ js_eval (toJSString script)
52eval script = liftIO $ js_eval (toJSString script)
53−foreign import javascript unsafe "$r = eval($1);"
53+foreign import javascript safe "$r = eval($1);"
54 js_eval :: JSString -> IO JSVal
54 js_eval :: JSString -> IO JSVal
55#else
55#else
56eval = evaluateScript . toJSString
56eval = evaluateScript . toJSString
jsaddle/src/Language/Javascript/JSaddle/Object.hs+5−6
@@ -526,12 +526,11 @@ array args = do
526 Object . coerce <$> fromListIO rargs
526 Object . coerce <$> fromListIO rargs
527
527
528-- | JavaScript's global object
528-- | JavaScript's global object
529−global :: Object
530#ifdef ghcjs_HOST_OS
529#ifdef ghcjs_HOST_OS
531−global = js_window
532−foreign import javascript unsafe "$r = window"
530+foreign import javascript unsafe "$r = globalThis"
533− js_window :: Object
531+ global :: Object
534#else
532#else
533+global :: Object
535global = Object . JSVal . unsafePerformIO $ newIORef 4
534global = Object . JSVal . unsafePerformIO $ newIORef 4
536#endif
535#endif
537
536
@@ -557,7 +556,7 @@ objCallAsFunction :: MakeArgs args
557objCallAsFunction f this args = do
556objCallAsFunction f this args = do
558 rargs <- makeArgs args >>= liftIO . Array.fromListIO
557 rargs <- makeArgs args >>= liftIO . Array.fromListIO
559 liftIO $ js_apply f this rargs
558 liftIO $ js_apply f this rargs
560−foreign import javascript unsafe "$r = $1.apply($2, $3)"
559+foreign import javascript safe "$r = $1.apply($2, $3)"
561 js_apply :: Object -> Object -> MutableJSArray -> IO JSVal
560 js_apply :: Object -> Object -> MutableJSArray -> IO JSVal
562#else
561#else
563objCallAsFunction f this args = do
562objCallAsFunction f this args = do
@@ -577,7 +576,7 @@ objCallAsConstructor :: MakeArgs args
577objCallAsConstructor f args = do
576objCallAsConstructor f args = do
578 rargs <- makeArgs args >>= liftIO . Array.fromListIO
577 rargs <- makeArgs args >>= liftIO . Array.fromListIO
579 liftIO $ js_new f rargs
578 liftIO $ js_new f rargs
580−foreign import javascript unsafe "\
579+foreign import javascript safe "\
581 switch($2.length) {\
580 switch($2.length) {\
582 case 0 : $r = new $1(); break;\
581 case 0 : $r = new $1(); break;\
583 case 1 : $r = new $1($2[0]); break;\
582 case 1 : $r = new $1($2[0]); break;\
jsaddle/src/Language/Javascript/JSaddle/Run.hs+2−1
@@ -227,10 +227,11 @@ runJavaScript sendBatch entryPoint = do
227 zipWithM_ putMVar resultMVars results
227 zipWithM_ putMVar resultMVars results
228 forM_ callbacksToFree $ \(JSValueReceived val) ->
228 forM_ callbacksToFree $ \(JSValueReceived val) ->
229 atomically (modifyTVar' callbacks (M.delete val))
229 atomically (modifyTVar' callbacks (M.delete val))
230− (_, Failure callbacksToFree results exception) -> do
230+ (_, Failure callbacksToFree results exception err) -> do
231 -- The exception will only be rethrown in Haskell if/when one of the
231 -- The exception will only be rethrown in Haskell if/when one of the
232 -- missing results (if any) is evaluated.
232 -- missing results (if any) is evaluated.
233 putStrLn "A JavaScript exception was thrown! (may not reach Haskell code)"
233 putStrLn "A JavaScript exception was thrown! (may not reach Haskell code)"
234+ putStrLn err
234 zipWithM_ putMVar resultMVars $ results <> repeat (ThrowJSValue exception)
235 zipWithM_ putMVar resultMVars $ results <> repeat (ThrowJSValue exception)
235 forM_ callbacksToFree $ \(JSValueReceived val) ->
236 forM_ callbacksToFree $ \(JSValueReceived val) ->
236 atomically (modifyTVar' callbacks (M.delete val))
237 atomically (modifyTVar' callbacks (M.delete val))
jsaddle/src/Language/Javascript/JSaddle/Run/Files.hs+3−38
@@ -13,7 +13,6 @@
13
13
14module Language.Javascript.JSaddle.Run.Files (
14module Language.Javascript.JSaddle.Run.Files (
15 indexHtml
15 indexHtml
16− , jsaddleJs
17 , initState
16 , initState
18 , runBatch
17 , runBatch
19 , ghcjsHelpers
18 , ghcjsHelpers
@@ -42,7 +41,7 @@ initState = "\
42 \ jsaddle_values.set(1, undefined);\n\
41 \ jsaddle_values.set(1, undefined);\n\
43 \ jsaddle_values.set(2, false);\n\
42 \ jsaddle_values.set(2, false);\n\
44 \ jsaddle_values.set(3, true);\n\
43 \ jsaddle_values.set(3, true);\n\
45− \ jsaddle_values.set(4, window);\n\
44+ \ jsaddle_values.set(4, globalThis);\n\
46 \ var jsaddle_index = 100;\n\
45 \ var jsaddle_index = 100;\n\
47 \ var expectedBatch = 1;\n\
46 \ var expectedBatch = 1;\n\
48 \ var lastResults = [0, {\"tag\": \"Success\", \"contents\": [[], []]}];\n\
47 \ var lastResults = [0, {\"tag\": \"Success\", \"contents\": [[], []]}];\n\
@@ -316,7 +315,8 @@ runBatch send sendSync = "\
316 \ catch (err) {\n\
315 \ catch (err) {\n\
317 \ var n = ++jsaddle_index;\n\
316 \ var n = ++jsaddle_index;\n\
318 \ jsaddle_values.set(n, err);\n\
317 \ jsaddle_values.set(n, err);\n\
318+ \ console.log(err);\n\
319− \ " <> send "{\"tag\": \"BatchResults\", \"contents\": [batch[2], {\"tag\": \"Failure\", \"contents\": [callbacksToFree, results, n]}]}" <> "\n\
319+ \ " <> send "{\"tag\": \"BatchResults\", \"contents\": [batch[2], {\"tag\": \"Failure\", \"contents\": [callbacksToFree, results, n, String(err)]}]}" <> "\n\
320 \ }\n\
320 \ }\n\
321 \ if(inCallback == 1) {\n\
321 \ if(inCallback == 1) {\n\
322 \ while(asyncBatch !== null) {\n\
322 \ while(asyncBatch !== null) {\n\
@@ -337,41 +337,6 @@ runBatch send sendSync = "\
337 \ runBatch(batch);\n\
337 \ runBatch(batch);\n\
338 \"
338 \"
339
339
340−-- Use this to generate this string for embedding
341−-- sed -e 's|\\|\\\\|g' -e 's|^| \\|' -e 's|$|\\n\\|' -e 's|"|\\"|g' data/jsaddle.js | pbcopy
342−jsaddleJs :: ByteString
343−jsaddleJs = "\
344− \if(typeof global !== \"undefined\") {\n\
345− \ global.window = global;\n\
346− \ global.WebSocket = require('ws');\n\
347− \}\n\
348− \\n\
349− \var connect = function() {\n\
350− \ var wsaddress =\n\
351− \ typeof window.location === \"undefined\"\n\
352− \ ? \"ws://localhost:3709/\"\n\
353− \ : window.location.protocol.replace('http', 'ws')+\"//\"+window.location.hostname+(window.location.port?(\":\"+window.location.port):\"\");\n\
354− \\n\
355− \ var ws = new WebSocket(wsaddress);\n\
356− \\n\
357− \ ws.onopen = function(e) {\n\
358− \ " <> initState <> "\
359− \\n\
360− \ ws.onmessage = function(e) {\n\
361− \ var batch = JSON.parse(e.data);\n\
362− \\n\
363− \ " <> runBatch (\a -> "ws.send(JSON.stringify(" <> a <> "));") Nothing <> "\
364− \ };\n\
365− \ };\n\
366− \ ws.onerror = function() {\n\
367− \ setTimeout(connect, 1000);\n\
368− \ };\n\
369− \}\n\
370− \\n\
371− \ " <> ghcjsHelpers <> "\
372− \connect();\n\
373− \"
374−
375ghcjsHelpers :: ByteString
340ghcjsHelpers :: ByteString
376ghcjsHelpers = "\
341ghcjsHelpers = "\
377 \function h$isNumber(o) {\
342 \function h$isNumber(o) {\
jsaddle/src/Language/Javascript/JSaddle/Types.hs+10−2
@@ -124,6 +124,7 @@ import Data.Aeson
124 (defaultOptions, genericToEncoding, ToJSON(..), FromJSON(..), Value)
124 (defaultOptions, genericToEncoding, ToJSON(..), FromJSON(..), Value)
125import GHC.Generics (Generic)
125import GHC.Generics (Generic)
126import Control.Monad.IO.Unlift (MonadUnliftIO)
126import Control.Monad.IO.Unlift (MonadUnliftIO)
127+import qualified Control.Monad.Fail as Fail
127#endif
128#endif
128
129
129#if MIN_VERSION_base(4,9,0) && defined(CHECK_UNCHECKED)
130#if MIN_VERSION_base(4,9,0) && defined(CHECK_UNCHECKED)
@@ -165,7 +166,7 @@ data JSContextRef = JSContextRef {
165type JSM = IO
166type JSM = IO
166#else
167#else
167newtype JSM a = JSM { unJSM :: ReaderT JSContextRef IO a }
168newtype JSM a = JSM { unJSM :: ReaderT JSContextRef IO a }
168− deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadThrow, MonadUnliftIO)
169+ deriving (Functor, Applicative, Monad, MonadIO, MonadFix, MonadThrow, MonadUnliftIO, Fail.MonadFail)
169
170
170instance MonadCatch JSM where
171instance MonadCatch JSM where
171 t `catch` c = JSM (unJSM (syncAfter t) `catch` \e -> unJSM (c e))
172 t `catch` c = JSM (unJSM (syncAfter t) `catch` \e -> unJSM (c e))
@@ -178,6 +179,13 @@ instance MonadMask JSM where
178 JSM $ uninterruptibleMask $ \unmask -> unJSM (a $ q unmask)
179 JSM $ uninterruptibleMask $ \unmask -> unJSM (a $ q unmask)
179 where q :: (ReaderT JSContextRef IO a -> ReaderT JSContextRef IO a) -> JSM a -> JSM a
180 where q :: (ReaderT JSContextRef IO a -> ReaderT JSContextRef IO a) -> JSM a -> JSM a
180 q unmask (JSM b) = syncAfter . JSM $ unmask b
181 q unmask (JSM b) = syncAfter . JSM $ unmask b
182+#if MIN_VERSION_exceptions(0,9,0)
183+ generalBracket acquire release use =
184+ JSM $ generalBracket
185+ (unJSM acquire)
186+ (\resource exitCase -> unJSM $ release resource exitCase)
187+ (unJSM . syncAfter . use)
188+#endif
181
189
182#endif
190#endif
183
191
@@ -496,7 +504,7 @@ instance ToJSON Result where
496instance FromJSON Result
504instance FromJSON Result
497
505
498data BatchResults = Success [JSValueReceived] [Result]
506data BatchResults = Success [JSValueReceived] [Result]
499− | Failure [JSValueReceived] [Result] JSValueReceived
507+ | Failure [JSValueReceived] [Result] JSValueReceived String
500 deriving (Show, Generic)
508 deriving (Show, Generic)
501
509
502instance ToJSON BatchResults where
510instance ToJSON BatchResults where
nix/hix.nixnew file+8
@@ -0,0 +1,8 @@
1+{pkgs, ...}:
2+{ modules = [({pkgs, ...}: {
3+ packages.webkit2gtk3-javascriptcore.components.library.doHaddock = false;
4+ })];
5+ shell.buildInputs = [ pkgs.nodejs ];
6+ shell.tools.cabal = {};
7+ shell.crossPlatforms = p: [ p.ghcjs ];
8+}
travis/build.sh+2−12
@@ -6,18 +6,8 @@ GHCVER=`ghc --numeric-version`
6
6
7JSADDLE_WARP_VERSION=`head -n2 jsaddle-warp/jsaddle-warp.cabal | tail -n1 | sed 's/[^0-9.]//g'`
7JSADDLE_WARP_VERSION=`head -n2 jsaddle-warp/jsaddle-warp.cabal | tail -n1 | sed 's/[^0-9.]//g'`
8
8
9−if [[ -d .cabal && -d .ghc ]]; then
10− cp -a .cabal .ghc /root
11−fi
12−
13cabal update
9cabal update
14−cabal new-build --constraint='Cabal>=1.24.2.0' 'jsaddle-warp:lib:jsaddle-warp' 'jsaddle-warp:test:test-tool'
10+cabal new-build 'jsaddle-warp:lib:jsaddle-warp' 'jsaddle-warp:test:test-tool'
15cd jsaddle-warp
11cd jsaddle-warp
16−GHC_PACKAGE_PATH=/opt/ghc/$GHCVER/lib/ghc-$GHCVER/package.conf.d:~/.cabal/store/ghc-$GHCVER/package.db:./dist-newstyle/packagedb/ghc-$GHCVER jsaddle_datadir=`pwd` ../dist-newstyle/build/jsaddle-warp-$JSADDLE_WARP_VERSION/build/test-tool/test-tool ../jsaddle-warp
12+GHC_PACKAGE_PATH=/opt/ghc/$GHCVER/lib/ghc-$GHCVER/package.conf.d:~/.cabal/store/ghc-$GHCVER/package.db:../dist-newstyle/packagedb/ghc-$GHCVER ../dist-newstyle/build/x86_64-linux/ghc-$GHCVER/jsaddle-warp-$JSADDLE_WARP_VERSION/t/test-tool/build/test-tool/test-tool ../jsaddle
17−
18−# update the cache
19−rm -rf .cabal
20−cp -a /root/.cabal ./
21−rm -rf .ghc
22−cp -a /root/.ghc ./
23
13