haste-lib-0.6.0.0: src/Haste.hs
{-# LANGUAGE ForeignFunctionInterface, EmptyDataDecls, OverloadedStrings #-}
-- | Haste's companion to the Prelude.
module Haste (
-- * Basic utility functions
JSString, JSAny, URL, MonadIO (..),
alert, prompt, eval, writeLog, catJSStr, fromJSStr,
-- * Location handling
onHashChange, setHash, getHash,
getLocationHref, setLocationHref, getLocationHostName, getLocationPort,
-- * Timers
Timer, Interval (..), setTimer, stopTimer,
-- * Fast conversions for JS-native types
JSType (..), JSNum (..), toString, fromString, convert,
-- * Reflection
getProgramId, getProgramJS
) where
import Haste.Prim
import Haste.Timer
import Haste.Prim.JSType
import Haste.Hash
import Haste.Foreign
import Control.Monad.IO.Class
jsAlert :: JSString -> IO ()
jsAlert = ffi "alert"
jsLog :: JSString -> IO ()
jsLog = ffi "(function(x){console.log(x);})"
jsPrompt :: JSString -> IO JSString
jsPrompt = ffi "(function(s){var x = prompt(s);\
\return (x === null) ? '' : x.toString();})"
jsEval :: JSString -> IO JSString
jsEval = ffi "(function(s){var x = eval(s);\
\return (typeof x === 'undefined') ? 'undefined' : x.toString();})"
-- | JavaScript @alert()@ function.
alert :: MonadIO m => JSString -> m ()
alert = liftIO . jsAlert
-- | JavaScript @prompt()@ function.
prompt :: MonadIO m => JSString -> m JSString
prompt = liftIO . jsPrompt
-- | JavaScript @eval()@ function.
eval :: MonadIO m => JSString -> m JSString
eval = liftIO . jsEval
-- | JavaScript @console.log()@.
writeLog :: MonadIO m => JSString -> m ()
writeLog = liftIO . jsLog
-- | Get the value of the @__haste_prog_id@ variable. Unless programmatically
-- changed, this variable contains the SHA3-256 hash of the currently
-- executing Haste program.
getProgramId :: MonadIO m => m JSString
getProgramId = liftIO getProgramId'
getProgramId' :: IO JSString
getProgramId' = ffi "(function(){return __haste_prog_id;})"
-- | Get the complete JavaScript source code of the currently executing Haste
-- program. On IE, this requires that the program's identifier, as returned
-- by 'getProgramId', has not been tampered with.
getProgramJS :: MonadIO m => m (Either URL JSString)
getProgramJS = liftIO $ do
(murl, msrc) <- getCurrentScript
return $ maybe (maybe impossible Right msrc) Left murl
where
impossible = error "impossible!"
-- | JS worker for 'getProgramJS'.
getCurrentScript :: IO (Maybe URL, Maybe JSString)
getCurrentScript = ffi "(function(){\
\ if(__haste_script_elem) {\
\ if(__haste_script_elem.innerHTML) {\
\ return [null, __haste_script_elem.innerHTML];\
\ } else {\
\ return [__haste_script_elem.src, null];\
\ }\
\ } else {\
\ var es = document.getElementsByTagName('SCRIPT');\
\ var re = new RegExp('var __haste_prog_id = \\'\\([0-9a-f]{64}\\)\\';');\
\ for(var i in es) {\
\ if(es[i].innerHTML) {\
\ var match = es[i].innerHTML.match(re);\
\ if(match && match[1] == __haste_prog_id) {\
\ return [null, es[i].innerHTML];\
\ }\
\ } else if(es[i].src) {\
\ var xhr = new XMLHttpRequest();\
\ xhr.open('GET', es[i].src, false);\
\ xhr.send();\
\ var match = xhr.responseText.match(re);\
\ if(match && match[1] == __haste_prog_id) {\
\ return [es[i].src, null];\
\ }\
\ }\
\ }\
\ }\
\ throw 'source of current program not found';\
\})"
-- | Get the current complete location URL.
getLocationHref :: MonadIO m => m URL
getLocationHref = liftIO getLocationHref'
getLocationHref' :: IO URL
getLocationHref' = ffi "(function(){return location.href;})"
-- | Set the location URL.
setLocationHref :: MonadIO m => URL -> m ()
setLocationHref href = liftIO (setLocationHref' href)
setLocationHref' :: URL -> IO ()
setLocationHref' = ffi "(function(href){location.href = href;})"
-- | Get the current location host name.
getLocationHostName :: MonadIO m => m JSString
getLocationHostName = liftIO getLocationHostName'
getLocationHostName' :: IO JSString
getLocationHostName' = ffi "(function(){return location.hostname;})"
-- | Get the current location port.
getLocationPort :: MonadIO m => m Int
getLocationPort = liftIO getLocationPort'
getLocationPort' :: IO Int
getLocationPort' = ffi "(function(){return location.port;})"