Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to implement Sidebar #18

Closed
kaizhang opened this issue Jul 10, 2017 · 5 comments
Closed

Try to implement Sidebar #18

kaizhang opened this issue Jul 10, 2017 · 5 comments

Comments

@kaizhang
Copy link

kaizhang commented Jul 10, 2017

This may not directly relate with this package. I am implementing the "sidebar" widget from Semantic UI. I'm new to both semui and reflex. And I had hard time to get the sidebar initialization process worked. I want to call $(.sidebar).sidebar({ dimPage: false}) after the sidebar is loaded (I found that it will lead to an error if this function is called before the elements are loaded). So I used the "Load" event. However, for some reasons the event never fired. Other than not being able to change the settings, my sidebar implementation works as expected. Here is the codes. Any suggestions? Thanks!

uiSidebar :: MonadWidget t m
          => UiSidebar    -- ^ Sidebar configuration
          -> m a  -- ^ Sidebar content
          -> m b  -- ^ Sidebar pusher
          -> (b -> Event t SidebarBehavior)   -- ^ Assign sidebar events
          -> m (a, b)
uiSidebar config content pusher getBeh = do
    (e1, res1) <- elClass' "div" "ui sidebar" content
    (e2, res2) <- elClass' "div" "pusher" pusher
    performEvent (DOM.liftJSM . uiTriggerSidebarAction (_element_raw e1) <$> getBeh res2)
    performEvent (DOM.liftJSM . configSidebar (_element_raw e1) .
        (const config) <$> domEvent Load e2)
    return (res1, res2)

uiTriggerSidebarAction :: DOM.Element -> SidebarBehavior -> DOM.JSM ()
uiTriggerSidebarAction e beh = js_sidebarAction e
                      (DOM.toJSString $ sidebarBehaviorString beh)

foreign import javascript unsafe "$($1).sidebar($2);"
    js_sidebarAction :: DOM.Element -> DOM.JSString -> DOM.JSM ()

configSidebar :: DOM.Element -> UiSidebar -> DOM.JSM ()
configSidebar e UiSidebar{..} = js_configSidebar e _uiSidebar_dimPage

foreign import javascript unsafe
    "$($1).sidebar({  \
        dimPage: $2   \
    });alert($2);"
    js_configSidebar :: DOM.Element -> Bool -> DOM.JSM ()

data SidebarBehavior = ShowSidebar
                     | HideSidebar
                     | ToggleSidebar
                     deriving (Eq, Ord, Enum)

sidebarBehaviorString :: SidebarBehavior -> T.Text
sidebarBehaviorString beh = case beh of
    ShowSidebar -> "show"
    HideSidebar -> "hide"
    ToggleSidebar -> "toggle"

data UiSidebar = UiSidebar
    { _uiSidebar_context :: T.Text    -- ^ Context which sidebar will appear inside
    , _uiSidebar_exclusive :: Bool    -- ^ Whether multiple sidebars can be open at once
    , _uiSidebar_closable :: Bool     -- ^ Whether sidebar can be closed by clicking on page
    , _uiSidebar_dimPage :: Bool      -- ^ Whether to dim page contents when sidebar is visible
    , _uiSidebar_scrollLock	:: Bool   -- ^ Whether to lock page scroll when sidebar is visible
    , _uiSidebar_returnScroll :: Bool -- ^ Whether to return to original scroll position when sidebar is hidden, automatically occurs with transition: scale
    , _uiSidebar_delaySetup	:: Bool   -- ^ When sidebar is initialized without the proper HTML, using this option will defer creation of DOM to use requestAnimationFrame.
    }

instance Default UiSidebar where
    def = UiSidebar
        { _uiSidebar_context = "body"
        , _uiSidebar_exclusive = False
        , _uiSidebar_closable = True
        , _uiSidebar_dimPage = False
        , _uiSidebar_scrollLock = False
        , _uiSidebar_returnScroll = False
        , _uiSidebar_delaySetup = False
        }
@tomsmalley
Copy link
Member

Try to instead use the event from getPostBuild:

pb <- getPostBuild
performEvent_ $ DOM.liftJSM . configSidebar (_element_raw e1) .
        (const config) <$> pb

@kaizhang
Copy link
Author

getPostBuild does return a usable event. But the event seems to occur before the "pusher" is loaded, because I still got the same error from semui: Sidebar: – "Had to add pusher element. For optimal performance make sure body content is inside a pusher element"
Where is the documentation of the getPostBuild function and why is the Load event never happened?

@kaizhang
Copy link
Author

domEvent Load does not work because onload only works for following tags: <body>, <frame>, <iframe>, <img>, <input type="image">, <link>, <script>, <style>.
I don't know why pb <- getPostBuild does not work. But I found pb <- delay 0 =<< getPostbuild works. Can anyone explain this?

@ryantrinkle
Copy link
Member

@kaizhang That's probably because the event from getPostBuild fires immediately after the widget is built - but usually before it's placed in the document. When you add the delay 0, you will generally delay until after the element has been placed in the document. If it's possible to write your code so that it works regardless of whether the widget is in the document or not, that's the most robust approach. Otherwise, there is a PR being worked on that will give you a nice way of doing things when the widget is mounted.

@kaizhang
Copy link
Author

@ryantrinkle That makes sense. To do what you suggested, I probably need to rewrite the js part of semantic UI in Haskell. I do not want to do that for now. I hope the PR can be merged soon. Right now I will just use a safe value for delay.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants