├── multiple-pages ├── .gitignore ├── Setup.lhs ├── data │ ├── main.js │ ├── hamlet.html │ ├── primes.html │ └── index.html ├── multiple-pages.cabal └── src │ └── Main.hs ├── fay-hello ├── js │ ├── Setup.hs │ ├── fay-hello-js.cabal │ ├── LICENSE │ └── Main.hs ├── install-integrated.sh ├── install-standalone.sh ├── Setup.lhs ├── fay-hello.cabal └── src │ └── Main.hs ├── try-purescript ├── Setup.hs ├── data │ ├── busy.gif │ ├── run_button.png │ └── tryps.css ├── codemirror │ ├── theme │ │ └── elegant.css │ ├── LICENSE │ ├── addon │ │ └── edit │ │ │ └── matchbrackets.js │ ├── lib │ │ └── codemirror.css │ └── mode │ │ └── haskell │ │ └── haskell.js ├── LICENSE ├── try-purescript.cabal ├── prepare.sh ├── README.markdown ├── Main.hs └── jsbits │ └── tryps.js ├── weblog ├── hello │ └── hello.hs ├── balls1 │ ├── ball.png │ ├── balls1.html │ └── balls1.hs ├── balls2 │ ├── ball.png │ ├── balls2.html │ └── balls2.hs ├── event │ ├── event.hs │ └── event.html ├── ffi │ └── ffi.hs ├── fibonacci │ └── fibonacci.hs ├── mouse │ ├── mouse.html │ └── mouse.hs ├── counter │ ├── counter.html │ └── counter.hs ├── calculator │ ├── calculator.html │ └── calculator.hs ├── sync │ ├── sync.hs │ └── sync.html ├── race │ ├── race.hs │ └── race.html └── build.sh ├── sources.txt ├── .gitignore ├── mloc-js ├── Setup.lhs ├── mloc-js.cabal └── src │ ├── Demo │ ├── LazyLoading.hs │ ├── DOM.hs │ ├── JavaScriptFFI.hs │ ├── Threading.hs │ └── Life.hs │ ├── WebKitUtils.hs │ └── Main.hs ├── ghcjs-hello ├── Setup.lhs ├── ghcjs-hello.cabal └── src │ └── Main.hs ├── webkit-hello ├── Setup.lhs ├── webkit-hello.cabal └── src │ └── Main.hs ├── webkit-sodium ├── Setup.lhs ├── webkit-sodium.cabal └── src │ ├── Game.hs │ ├── Main.hs │ ├── Engine.hs │ └── Freecell.hs ├── travis └── gtk.sh ├── .travis.yml ├── threads └── threads.hs └── README.md /multiple-pages/.gitignore: -------------------------------------------------------------------------------- 1 | /*.lkshf 2 | -------------------------------------------------------------------------------- /fay-hello/js/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /try-purescript/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /weblog/hello/hello.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | main = putStrLn "Hello World!" 4 | -------------------------------------------------------------------------------- /sources.txt: -------------------------------------------------------------------------------- 1 | ./ghcjs-hello 2 | ./multiple-pages 3 | ./webkit-sodium 4 | ./mloc-js 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | cabal-dev 3 | *.o 4 | *.hi 5 | *.chi 6 | *.chs.h 7 | /.shelly/ 8 | /gtk2hs/ 9 | -------------------------------------------------------------------------------- /weblog/balls1/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghcjs/ghcjs-examples/HEAD/weblog/balls1/ball.png -------------------------------------------------------------------------------- /weblog/balls2/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghcjs/ghcjs-examples/HEAD/weblog/balls2/ball.png -------------------------------------------------------------------------------- /fay-hello/install-integrated.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cabal install 3 | { 4 | cd js 5 | cabal install 6 | } 7 | 8 | -------------------------------------------------------------------------------- /try-purescript/data/busy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghcjs/ghcjs-examples/HEAD/try-purescript/data/busy.gif -------------------------------------------------------------------------------- /fay-hello/install-standalone.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cabal install 3 | ( 4 | cd js 5 | ghcjs-cabal install 6 | ) 7 | 8 | -------------------------------------------------------------------------------- /try-purescript/data/run_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghcjs/ghcjs-examples/HEAD/try-purescript/data/run_button.png -------------------------------------------------------------------------------- /fay-hello/Setup.lhs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/runhaskell 2 | > module Main where 3 | > import Distribution.Simple 4 | > main :: IO () 5 | > main = defaultMain 6 | 7 | -------------------------------------------------------------------------------- /mloc-js/Setup.lhs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/runhaskell 2 | > module Main where 3 | > import Distribution.Simple 4 | > main :: IO () 5 | > main = defaultMain 6 | 7 | -------------------------------------------------------------------------------- /ghcjs-hello/Setup.lhs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/runhaskell 2 | > module Main where 3 | > import Distribution.Simple 4 | > main :: IO () 5 | > main = defaultMain 6 | 7 | -------------------------------------------------------------------------------- /multiple-pages/Setup.lhs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/runhaskell 2 | > module Main where 3 | > import Distribution.Simple 4 | > main :: IO () 5 | > main = defaultMain 6 | 7 | -------------------------------------------------------------------------------- /webkit-hello/Setup.lhs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/runhaskell 2 | > module Main where 3 | > import Distribution.Simple 4 | > main :: IO () 5 | > main = defaultMain 6 | 7 | -------------------------------------------------------------------------------- /webkit-sodium/Setup.lhs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/runhaskell 2 | > module Main where 3 | > import Distribution.Simple 4 | > main :: IO () 5 | > main = defaultMain 6 | 7 | -------------------------------------------------------------------------------- /multiple-pages/data/main.js: -------------------------------------------------------------------------------- 1 | window.onload = function(){ 2 | goog.debug.Console.autoInstall(); 3 | $hs_loadPath = "../../bin/multiple-pages.trampoline.jsexe/"; 4 | 5 | // Must be called first 6 | $hs_init(); 7 | $hs_consoleInitAndRunIO([$$ZCMain_main]); 8 | } 9 | 10 | -------------------------------------------------------------------------------- /travis/gtk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | sudo apt-get update -qq 3 | sudo apt-get --no-install-recommends install darcs libwebkitgtk-3.0-dev 4 | git clone https://github.com/yesodweb/cabal-meta.git 5 | darcs get --lazy http://patch-tag.com/r/hamish/gtk2hs 6 | cabal install ./gtk2hs/tools 7 | 8 | -------------------------------------------------------------------------------- /fay-hello/fay-hello.cabal: -------------------------------------------------------------------------------- 1 | name: fay-hello 2 | version: 0.0.1 3 | cabal-version: >=1.2 4 | build-type: Simple 5 | license: BSD3 6 | license-file: "" 7 | description: 8 | data-dir: "" 9 | 10 | executable fay-hello 11 | build-depends: base -any, blaze-html -any, filepath -any, 12 | hamlet -any, shakespeare-js -any, 13 | text -any, blaze-markup -any, ghcjs -any, 14 | fay-hello-js -any 15 | main-is: Main.hs 16 | buildable: True 17 | hs-source-dirs: src 18 | 19 | -------------------------------------------------------------------------------- /weblog/event/event.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Main where 4 | 5 | import JavaScript.JQuery 6 | import JavaScript.JQuery.Internal 7 | import Data.Default 8 | import qualified Data.Text as T 9 | 10 | main = do 11 | b <- select "body" 12 | append "
" b 13 | m <- select ".mouse" 14 | mousemove (handler m) def b 15 | 16 | handler :: JQuery -> Event -> IO () 17 | handler m e = do 18 | x <- pageX e 19 | y <- pageY e 20 | setText (T.pack $ show (x,y)) m 21 | return () 22 | 23 | -------------------------------------------------------------------------------- /fay-hello/js/fay-hello-js.cabal: -------------------------------------------------------------------------------- 1 | name: fay-hello-js 2 | version: 0.1.0.0 3 | license: BSD3 4 | license-file: LICENSE 5 | build-type: Simple 6 | cabal-version: >=1.8 7 | 8 | library 9 | build-depends: base >= 4 && < 5, transformers, template-haskell 10 | exposed-modules: Paths_fay_hello_js 11 | 12 | executable fay-hello-js 13 | build-depends: base >= 4 && < 5, fay, blaze-html ==0.5.*, text ==0.11.*, ghc-prim ==0.2.*, transformers, template-haskell 14 | Main-Is: Main.hs 15 | 16 | -------------------------------------------------------------------------------- /weblog/ffi/ffi.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE JavaScriptFFI, CPP #-} 2 | 3 | module Main where 4 | 5 | #ifdef __GHCJS__ 6 | foreign import javascript unsafe "document.write($1+'
');" writeNumber :: Int -> IO () 7 | foreign import javascript interruptible "setTimeout($c, $1);" delay :: Int -> IO () 8 | #else 9 | writeNumber = error "writeNumber: only available from JavaScript" 10 | delay = error "delay: only available from JavaScript" 11 | #endif 12 | 13 | main :: IO () 14 | main = mapM_ (\x -> writeNumber x >> delay 1000) [1..1000] 15 | 16 | -------------------------------------------------------------------------------- /webkit-hello/webkit-hello.cabal: -------------------------------------------------------------------------------- 1 | name: webkit-hello 2 | version: 0.0.1 3 | cabal-version: >=1.2 4 | build-type: Simple 5 | license: BSD3 6 | license-file: "" 7 | description: 8 | data-dir: "" 9 | 10 | executable webkit-hello 11 | build-depends: base -any, 12 | glib -any, 13 | gtk -any, 14 | webkit >= 0.12.5, 15 | ghcjs-dom -any, 16 | mtl -any 17 | main-is: Main.hs 18 | buildable: True 19 | hs-source-dirs: src 20 | ghc-options: -threaded -rtsopts 21 | -------------------------------------------------------------------------------- /weblog/fibonacci/fibonacci.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ScopedTypeVariables #-} 2 | module Main where 3 | 4 | import Control.Concurrent 5 | import qualified Control.Exception as E 6 | import Control.Monad 7 | 8 | -- this is inefficient on purpose 9 | fib :: Int -> Int 10 | fib 0 = 0 11 | fib 1 = 1 12 | fib n = fib (n-1) + fib (n-2) 13 | 14 | fib38 = fib 38 15 | 16 | printFib = print fib38 `E.catch` \(_::E.SomeException) -> putStrLn "not finished" 17 | 18 | main = forever $ do 19 | tid <- forkIO printFib 20 | threadDelay 1000000 21 | throwTo tid E.Overflow 22 | -------------------------------------------------------------------------------- /weblog/event/event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /weblog/mouse/mouse.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /weblog/balls1/balls1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /weblog/balls2/balls2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /weblog/counter/counter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /weblog/calculator/calculator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 18 | 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: haskell 2 | before_install: 3 | - sudo apt-get update -qq 4 | - sudo apt-get --no-install-recommends install darcs libwebkitgtk-3.0-dev 5 | - mkdir vendor 6 | - cd vendor 7 | - darcs get --lazy http://patch-tag.com/r/hamish/gtk2hs 8 | - cabal install ./gtk2hs/tools 9 | - cd .. 10 | install: 11 | - cabal install cabal-meta cabal-src 12 | - cabal-meta install -fwebkit1-8 -fgtk3 --force-reinstalls || cabal-meta install -fwebkit1-8 -fgtk3 --force-reinstalls 13 | script: 14 | - cd ghcjs-hello 15 | - cabal test 16 | - cd ../webkit-sodium 17 | - cabal test 18 | - cd ../multiple-pages 19 | - cabal test 20 | notifications: 21 | irc: 22 | channels: "irc.freenode.net#ghcjs" 23 | email: true 24 | -------------------------------------------------------------------------------- /multiple-pages/data/hamlet.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Multiple Pages - Hamlet 8 | 9 | 10 |

Multiple Pages - Hamlet

11 |

Have you tried hamlet?

12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /webkit-sodium/webkit-sodium.cabal: -------------------------------------------------------------------------------- 1 | name: webkit-sodium 2 | version: 0.0.1 3 | cabal-version: >=1.2 4 | build-type: Simple 5 | license: AllRightsReserved 6 | description: 7 | 8 | library 9 | build-depends: QuickCheck -any, base -any, mtl -any, 10 | sodium -any, array -any, filepath -any, random -any, ghcjs-dom -any, 11 | jsaddle -any, lens -any 12 | 13 | exposed-modules: Engine, Freecell, Game 14 | hs-source-dirs: src 15 | 16 | executable freecell 17 | build-depends: QuickCheck -any, base -any, mtl -any, 18 | sodium -any, array -any, filepath -any, random -any, ghcjs-dom -any, 19 | jsaddle -any, lens -any 20 | 21 | main-is: Main.hs 22 | buildable: True 23 | hs-source-dirs: src 24 | ghc-options: -threaded -rtsopts 25 | -------------------------------------------------------------------------------- /multiple-pages/data/primes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Multiple Pages - Primes 8 | 9 | 10 |

Multiple Pages - Primes

11 |

This page has a regular input element and suggestion. 12 | Our "custom browser" knows how to augment this with the 13 | code to validate the prime as it is entered

14 | 15 | enter a prime 16 | 17 | 18 | -------------------------------------------------------------------------------- /weblog/sync/sync.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Main where 4 | 5 | import GHCJS.Types 6 | import GHCJS.Foreign 7 | 8 | import Data.Text (Text) 9 | import Control.Applicative 10 | import Text.Read (readMaybe) 11 | 12 | main = do 13 | o <- newObj 14 | setProp ("input"::Text) ("123"::JSString) o 15 | factorial o 16 | r <- getProp ("output"::Text) o 17 | putStrLn (fromJSString r) 18 | 19 | factorial :: JSRef () -> IO () 20 | factorial ref = do 21 | x <- fromJSString <$> getProp ("input"::Text) ref 22 | let r = case readMaybe x of 23 | Just n | n < 0 || n > 5000 -> "invalid input" 24 | Just n -> toJSString . show . fact $ n 25 | Nothing -> "parse error" 26 | setProp ("output"::Text) r ref 27 | where 28 | fact :: Integer -> Integer 29 | fact n = product [1..n] 30 | -------------------------------------------------------------------------------- /try-purescript/codemirror/theme/elegant.css: -------------------------------------------------------------------------------- 1 | .cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom {color: #762;} 2 | .cm-s-elegant span.cm-comment {color: #262; font-style: italic; line-height: 1em;} 3 | .cm-s-elegant span.cm-meta {color: #555; font-style: italic; line-height: 1em;} 4 | .cm-s-elegant span.cm-variable {color: black;} 5 | .cm-s-elegant span.cm-variable-2 {color: #b11;} 6 | .cm-s-elegant span.cm-qualifier {color: #555;} 7 | .cm-s-elegant span.cm-keyword {color: #730;} 8 | .cm-s-elegant span.cm-builtin {color: #30a;} 9 | .cm-s-elegant span.cm-link {color: #762;} 10 | .cm-s-elegant span.cm-error {background-color: #fdd;} 11 | 12 | .cm-s-elegant .CodeMirror-activeline-background {background: #e8f2ff !important;} 13 | .cm-s-elegant .CodeMirror-matchingbracket {outline:1px solid grey; color:black !important;} 14 | -------------------------------------------------------------------------------- /multiple-pages/multiple-pages.cabal: -------------------------------------------------------------------------------- 1 | name: multiple-pages 2 | version: 0.0.1 3 | cabal-version: >=1.2 4 | build-type: Simple 5 | license: BSD3 6 | license-file: "" 7 | synopsis: Dynamic web site build on multiple HTML pages 8 | description: Shows how to add GHCJS support to static HTML files or server generated HTML files. 9 | . 10 | All the files run Main.main, but it simply detects the page and loads and runs the pages "main" function. 11 | data-files: *.html 12 | data-dir: data 13 | 14 | executable multiple-pages 15 | build-depends: text >=0.11.2.3 && <0.12, hamlet >=1.1.0.2 && <1.2, 16 | blaze-html >=0.5.0.0 && <0.7, webkit >=0.12.5 && <0.13, 17 | mtl >=2.1.1 && <2.2, ghcjs-dom >=0.0.1 && <0.1, base -any 18 | main-is: Main.hs 19 | buildable: True 20 | hs-source-dirs: src 21 | 22 | -------------------------------------------------------------------------------- /ghcjs-hello/ghcjs-hello.cabal: -------------------------------------------------------------------------------- 1 | name: ghcjs-hello 2 | version: 0.0.1 3 | cabal-version: >=1.8 4 | build-type: Simple 5 | license: BSD3 6 | 7 | flag jmacro 8 | Description: Include some JMacro support 9 | Default: False 10 | 11 | executable ghcjs-hello 12 | build-depends: deepseq >=1.3.0.2 && <1.4, lens -any, 13 | containers -any, random -any, 14 | template-haskell -any, base -any, blaze-html -any, filepath -any, 15 | hamlet -any, text -any, blaze-markup -any, shakespeare -any, 16 | ghcjs-dom >=0.1.1.0 && <0.2, mtl -any, sodium -any, webkit-sodium -any, 17 | jsaddle >=0.2.0.0 && <0.3 18 | 19 | if flag(jmacro) 20 | build-depends: jmacro >=0.6.3 && <0.8 21 | 22 | main-is: Main.hs 23 | buildable: True 24 | hs-source-dirs: src 25 | ghc-options: -threaded -with-rtsopts=-N3 26 | 27 | -------------------------------------------------------------------------------- /weblog/race/race.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE JavaScriptFFI, CPP #-} 2 | module Main where 3 | 4 | import Control.Monad 5 | import Control.Concurrent 6 | import GHCJS.Foreign 7 | import GHCJS.Types 8 | 9 | import Data.Text (pack) 10 | 11 | #ifdef __GHCJS__ 12 | foreign import javascript unsafe "document.getElementById($1).style.left = '' + $2 + 'px'" 13 | setPos :: JSString -> Int -> IO () 14 | #else 15 | setPos = error "setPos: only available in JavaScript" 16 | #endif 17 | 18 | main :: IO () 19 | main = mapM_ runRacer [1..10] 20 | 21 | runRacer :: Int -> IO () 22 | runRacer n = void $ forkIO $ do 23 | doRace (toJSString $ "racer" ++ show n) 24 | 25 | doRace :: JSString -> IO () 26 | doRace str = go (0::Int) 27 | where 28 | go n | n > 800 = go 0 29 | | otherwise = do 30 | setPos str n 31 | threadDelay 1 32 | go (n+1) 33 | 34 | x = pack "abc" -- workaround, sometimes the dependencies for text aren't linked without this, need to investigate 35 | -------------------------------------------------------------------------------- /weblog/sync/sync.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 28 | 29 | -------------------------------------------------------------------------------- /weblog/counter/counter.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Main where 4 | 5 | import Control.Monad 6 | import Control.Monad.IO.Class 7 | import Data.Default 8 | import Data.Text (Text) 9 | import qualified Data.Text as T 10 | 11 | import JavaScript.JQuery hiding (Event) 12 | 13 | import FRP.Sodium 14 | 15 | main :: IO () 16 | main = do 17 | body <- select "body" 18 | buttonEvent <- reactiveButton "Click Me!" body 19 | counterDiv <- select "
" 20 | appendJQuery counterDiv body 21 | sync $ do 22 | counter <- count buttonEvent 23 | listen (values counter) (\n -> void $ 24 | setText (T.pack . show $ n) counterDiv) 25 | return () 26 | 27 | reactiveButton :: Text -> JQuery -> IO (Event ()) 28 | reactiveButton label parent = do 29 | (evt, a) <- sync newEvent 30 | button <- select "