{-# 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;})"