Sidebar.purs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. module PureTabs.Sidebar where
  2. import Browser.Runtime as Runtime
  3. import Browser.Tabs (Tab(..), TabId, WindowId)
  4. import Browser.Tabs.OnUpdated (ChangeInfo(..))
  5. import Browser.Windows (getCurrent)
  6. import Control.Alternative (pure)
  7. import Control.Bind ((>=>), (>>=))
  8. import Data.CommutativeRing ((+))
  9. import Data.Eq ((==))
  10. import Data.Foldable (traverse_)
  11. import Data.Function (flip)
  12. import Data.Maybe (Maybe(..), maybe)
  13. import Data.Monoid ((<>))
  14. import Data.Show (show)
  15. import Data.Unit (unit)
  16. import Debug.Trace (traceM)
  17. import Effect (Effect)
  18. import Effect.Aff (Aff, launchAff_)
  19. import Effect.Class (liftEffect)
  20. import Effect.Console (log)
  21. import JQuery as J
  22. import JQuery.Ext (after) as J
  23. import Prelude (Unit, bind, ($), discard)
  24. import PureTabs.Model (BackgroundEvent(..), SidebarEvent(..))
  25. main :: Effect Unit
  26. main = do
  27. log "started sidebar"
  28. port <- Runtime.connect
  29. launchAff_ $ runSidebar port
  30. where
  31. runSidebar :: Runtime.Port -> Aff Unit
  32. runSidebar port = do
  33. currentWindow <- getCurrent
  34. liftEffect $ initSidebar port currentWindow.id
  35. initSidebar :: Runtime.Port -> WindowId -> Effect Unit
  36. initSidebar port winId = do
  37. log $ "windowId " <> (show winId)
  38. Runtime.postMessageJson port $ SbHasWindowId winId
  39. tabsDiv <- J.select "#tabs"
  40. _ <- Runtime.onMessageJsonAddListener port $ onMsg tabsDiv
  41. pure unit
  42. where
  43. onMsg :: J.JQuery -> BackgroundEvent -> Effect Unit
  44. onMsg contentDiv event = case event of
  45. BgTabCreated tab -> do
  46. tabElem <- createTabElement port tab
  47. J.append tabElem contentDiv
  48. pure unit
  49. BgTabDeleted tabId -> deleteTabElement tabId
  50. BgInitialTabList tabs -> traverse_ (createTabElement port >=> (flip J.append) contentDiv) tabs
  51. BgTabUpdated tid cinfo tab -> updateTabInfo tid cinfo tab
  52. BgTabActived prev new -> activateTab prev new
  53. BgTabMoved tid prevPos newPos -> moveTab tid prevPos newPos
  54. _ -> log "received unsupported message type"
  55. createTabElement :: Runtime.Port -> Tab -> Effect J.JQuery
  56. createTabElement port (Tab tab) = do
  57. tabDiv <- J.create "<div>"
  58. J.setAttr "class" "tab" tabDiv
  59. J.setAttr "id" tab.id tabDiv
  60. J.on "click" onTabClick tabDiv
  61. if tab.active then (J.addClass "active" tabDiv) else (pure unit)
  62. -- favicon
  63. faviconDiv <- J.create "<div>"
  64. J.addClass "tab-favicon" faviconDiv
  65. setFaviconUrl tab.favIconUrl faviconDiv
  66. J.append faviconDiv tabDiv
  67. -- title
  68. tabTitle <- J.create "<div>"
  69. J.addClass "tab-title" tabTitle
  70. J.setText tab.title tabTitle
  71. J.append tabTitle tabDiv
  72. -- close button
  73. closeButton <- createCloseButton
  74. J.append closeButton tabDiv
  75. J.on "click" onCloseClick closeButton
  76. pure tabDiv
  77. where
  78. onCloseClick :: J.JQueryEvent -> J.JQuery -> Effect Unit
  79. onCloseClick event j = Runtime.postMessageJson port $ SbTabDeleted tab.id
  80. onTabClick :: J.JQueryEvent -> J.JQuery -> Effect Unit
  81. onTabClick event j = Runtime.postMessageJson port $ SbTabActived tab.id
  82. createCloseButton :: Effect J.JQuery
  83. createCloseButton = do
  84. parent <- J.create "<div>"
  85. J.addClass "close-button-parent" parent
  86. outer <- J.create "<div>"
  87. J.addClass "close-button-outer" outer
  88. J.append outer parent
  89. inner <- J.create "<div>"
  90. J.addClass "close-button-inner" inner
  91. J.append inner outer
  92. pure parent
  93. setFaviconUrl :: Maybe String -> J.JQuery -> Effect Unit
  94. setFaviconUrl Nothing div = pure unit
  95. setFaviconUrl (Just favData) div = J.css { "background-image": favUrl } div
  96. where
  97. favUrl = "url(" <> favData <> ")"
  98. deleteTabElement :: TabId -> Effect Unit
  99. deleteTabElement tabId = do
  100. div <- J.select ("#" <> show tabId)
  101. J.remove div
  102. updateTabInfo :: TabId -> ChangeInfo -> Tab -> Effect Unit
  103. updateTabInfo tid (ChangeInfo cinfo) (Tab tab) = do
  104. tabTitleDiv <- J.select ("#" <> (show tid) <> " > .tab-title")
  105. let
  106. newTitle = case cinfo.status of
  107. Just "loading" -> Just "Loading ..."
  108. _ -> Just tab.title
  109. maybe (pure unit) (\t -> J.setText t tabTitleDiv) newTitle
  110. tabFaviconDiv <- J.select ("#" <> (show tid) <> " > .tab-favicon")
  111. setFaviconUrl cinfo.favIconUrl tabFaviconDiv
  112. activateTab :: (Maybe TabId) -> TabId -> Effect Unit
  113. activateTab prev new = do
  114. maybe (pure unit) (\p -> (J.select ("#" <> (show p))) >>= J.setClass "active" false) prev
  115. newTab <- J.select ("#" <> (show new))
  116. J.setClass "active" true newTab
  117. moveTab :: TabId -> Int -> Int -> Effect Unit
  118. moveTab tabId prev new =
  119. do
  120. tabDiv <- J.select $ "#" <> show tabId
  121. J.remove tabDiv
  122. if new == 0 then do
  123. firstChild <- J.select $ "#tabs > .tab:nth-child(" <> (show $ new + 1) <> ")"
  124. J.before tabDiv firstChild
  125. else do
  126. child <- J.select $ "#tabs > .tab:nth-child(" <> (show $ new) <> ")"
  127. J.after tabDiv child