Skip to content

Instantly share code, notes, and snippets.

@mmaz
Last active July 22, 2017 18:22
Show Gist options
  • Save mmaz/5fc96b5554e0d8666ac7 to your computer and use it in GitHub Desktop.
Save mmaz/5fc96b5554e0d8666ac7 to your computer and use it in GitHub Desktop.
add Google's Material Design Lite to Reflex
import GHCJS.DOM.Types (Element, unElement)
import GHCJS.DOM.Element (toElement)
import GHCJS.Prim (JSRef)
-- http://www.getmdl.io/started/index.html#dynamic
#ifdef __GHCJS__
foreign import javascript unsafe "componentHandler.upgradeElement($1);"
materialInitJS :: JSRef Element -> IO ()
#else
materialInitJS = error "y u no javascript?"
#endif
rippleButton :: MonadWidget t m => ...
rippleButton = do
...
(myReflexEl, _) <- el' "button" $ text "Ripples!!!"
let jsel = unElement $ toElement $ _el_element myReflexEl
pb <- getPostBuild
performEvent_ $ (liftIO $ materialInitJS jsel) <$ pb
...
<!DOCTYPE html>
<html>
<head>
<script language="javascript" src="rts.js"></script>
<script language="javascript" src="lib.js"></script>
<script language="javascript" src="out.js"></script>
<link rel="stylesheet" href="https://storage.googleapis.com/code.getmdl.io/1.0.4/material.indigo-pink.min.css">
<script src="https://storage.googleapis.com/code.getmdl.io/1.0.4/material.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
</head>
<body>
</body>
<script language="javascript" src="runmain.js" defer></script>
</html>
@oliver-batchelor
Copy link

No need for performEvent_ and getPostBuild

Just use:
liftIO $ materialInitJS jsel

@mmaz
Copy link
Author

mmaz commented Sep 29, 2015

@Saulzar When chatting with @ryantrinkle on IRC, he mentioned a potential issue with FFI calls on dynamic elements:

ryantrinkle: one thing to note is that at the time your widget is being built, it is usually not actually on the page

So I am not clear on whether it is necessary or not, but I assume it is based on his comment. Maybe he can chime in though?

@alltom
Copy link

alltom commented Oct 3, 2016

The types have changed a little since this was originally posted. Here's the code I wrote for MDL text inputs:

import GHCJS.DOM.Element (toElement)
import qualified GHCJS.DOM.Types as GDT
import qualified GHCJS.Types as GT

foreign import javascript unsafe "componentHandler.upgradeElement($1);"
  materialInitJS :: GT.JSVal -> IO ()

materialInitialize :: MonadWidget t m => GDT.HTMLElement -> m ()
materialInitialize el = do
  let jsel = GDT.unElement $ toElement $ el
  pb <- getPostBuild
  performEvent_ $ (liftIO $ materialInitJS jsel) <$ pb

materialTextInput :: MonadWidget t m => Text -> Text -> m (TextInput t)
materialTextInput domId label = do
  (container, t) <- elAttr' "div" (Map.singleton "class" "mdl-textfield mdl-js-textfield mdl-textfield--floating-label") $ do
    let attrMap = Map.fromList [("class", "mdl-textfield__input"), ("id", domId)] :: Map.Map Text Text
    t <- textInput $ def & textInputConfig_attributes .~ (constDyn attrMap)
    elAttr "label" (Map.fromList [("class", "mdl-textfield__label"), ("for", domId)]) $ text label
    return t
  materialInitialize $ _element_raw container
  return t

FWIW, MDL's sample code also calls componentHandler.upgradeElement() before adding the element to the page, so that's probably not a problem. It does probably need to be called after the attributes are set (e.g. class="mdl-textfield"), though, which I think happens in post-build?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment