Model.purs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. module PureTabs.Model
  2. ( Window
  3. , GlobalState
  4. , _active
  5. , _id
  6. , _index
  7. , _port
  8. , _portFromWindow
  9. , _portFromWindowId
  10. , _positions
  11. , _tabFromTabIdAndWindow
  12. , _tabFromWindow
  13. , _tabId
  14. , _tabs
  15. , _tabWindowId
  16. , _windowIdToWindow
  17. , _windows
  18. , initialGlobalState
  19. , tabsToGlobalState
  20. , BackgroundEvent(..)
  21. , SidebarEvent(..)
  22. ) where
  23. import Browser.Runtime (Port)
  24. import Browser.Tabs (TabId(..), WindowId, Tab(..))
  25. import Browser.Tabs.OnUpdated (ChangeInfo(..))
  26. import Control.Alternative (empty)
  27. import Control.Bind (join)
  28. import Control.Category ((>>>), (<<<))
  29. import Data.Array (sortBy)
  30. import Data.Function (on, ($))
  31. import Data.Functor (map)
  32. import Data.Generic.Rep (class Generic)
  33. import Data.Generic.Rep.Show (genericShow)
  34. import Data.Lens (Lens', Traversal', _Just, view)
  35. import Data.Lens.At (at)
  36. import Data.Lens.Iso.Newtype (_Newtype)
  37. import Data.Lens.Record (prop)
  38. import Data.List (List(..), catMaybes, concat, head, singleton)
  39. import Data.Map as M
  40. import Data.Maybe (Maybe(..))
  41. import Data.Ord (compare)
  42. import Data.Show (class Show)
  43. import Data.Symbol (SProxy(..))
  44. import Data.Tuple (Tuple(..), fst, snd, uncurry)
  45. import Data.Tuple.Nested ((/\))
  46. type GlobalState
  47. = { windows :: M.Map WindowId Window
  48. }
  49. type Window
  50. = { positions :: Array TabId
  51. , tabs :: M.Map TabId Tab
  52. , port :: Maybe Port
  53. }
  54. _tabs :: forall a r. Lens' { tabs :: a | r } a
  55. _tabs = prop (SProxy :: _ "tabs")
  56. _port :: forall a r. Lens' { port :: a | r } a
  57. _port = prop (SProxy :: _ "port")
  58. _windows :: forall a r. Lens' { windows :: a | r } a
  59. _windows = prop (SProxy :: _ "windows")
  60. _title :: forall a r. Lens' { title :: a | r } a
  61. _title = prop (SProxy :: _ "title")
  62. _index :: forall a r. Lens' { index :: a | r } a
  63. _index = prop (SProxy :: _ "index")
  64. _tabTitle :: Lens' Tab String
  65. _tabTitle = _Newtype <<< _title
  66. _id :: forall a r. Lens' { id :: a | r } a
  67. _id = prop (SProxy :: _ "id")
  68. _active :: forall a r. Lens' { active :: a | r } a
  69. _active = prop (SProxy :: _ "active")
  70. _tabId :: Lens' Tab TabId
  71. _tabId = _Newtype <<< _id
  72. _windowId :: forall a r. Lens' { windowId :: a | r } a
  73. _windowId = prop (SProxy :: _ "windowId")
  74. _positions :: forall a r. Lens' { positions :: a | r } a
  75. _positions = prop (SProxy :: _ "positions")
  76. _tabWindowId :: Lens' Tab WindowId
  77. _tabWindowId = _Newtype <<< _windowId
  78. _portFromWindow :: Tab -> Traversal' GlobalState Port
  79. _portFromWindow (Tab tab) = _portFromWindowId tab.windowId
  80. _portFromWindowId :: WindowId -> Traversal' GlobalState Port
  81. _portFromWindowId wid = _windowIdToWindow wid <<< _port <<< _Just
  82. _windowIdToWindow :: WindowId -> Traversal' GlobalState Window
  83. _windowIdToWindow wid = _windows <<< (at wid) <<< _Just
  84. _tabFromWindow :: Tab -> Traversal' GlobalState (Maybe Tab)
  85. _tabFromWindow (Tab tab) = _windowIdToWindow tab.windowId <<< _tabs <<< (at tab.id)
  86. _tabFromTabIdAndWindow :: GlobalState -> TabId -> Maybe Tab
  87. _tabFromTabIdAndWindow s tabId =
  88. let
  89. allWindows = M.values s.windows
  90. allTabs = map (view _tabs) allWindows
  91. matchingTabId = map (M.lookup tabId) allTabs
  92. in
  93. join $ head matchingTabId
  94. initialGlobalState :: GlobalState
  95. initialGlobalState =
  96. { windows: M.empty
  97. }
  98. tabsToGlobalState :: List Tab -> GlobalState
  99. tabsToGlobalState tabs = { windows: tabsToWindows tabs }
  100. where
  101. tabsToWindows :: List Tab -> M.Map WindowId Window
  102. tabsToWindows tabs' = M.fromFoldableWith merge $ map mapTab tabs'
  103. merge :: Window -> Window -> Window
  104. merge w1 w2 =
  105. let
  106. mergedMap = M.union w1.tabs w2.tabs
  107. in
  108. { tabs: mergedMap
  109. , port: Nothing
  110. -- TODO do that after building the state, to avoid going creating a new list each time
  111. , positions: (mapPositions >>> (sortBy (compare `on` snd)) >>> (map fst)) mergedMap
  112. }
  113. mapTab :: Tab -> Tuple WindowId Window
  114. mapTab (Tab t) = Tuple t.windowId { tabs: M.singleton t.id (Tab t), port: Nothing, positions: empty }
  115. mapPositions :: M.Map TabId Tab -> Array (Tuple TabId Int)
  116. mapPositions = M.toUnfoldableUnordered >>> (map \(Tuple tid (Tab t)) -> tid /\ t.index)
  117. data BackgroundEvent
  118. = BgInitialTabList (Array Tab)
  119. | BgTabCreated Tab
  120. | BgTabDeleted TabId
  121. | BgTabUpdated TabId ChangeInfo Tab
  122. | BgTabMoved TabId Int Int
  123. | BgTabActived (Maybe TabId) TabId
  124. | BgTabAttached Tab
  125. | BgTabDetached TabId
  126. | BgTabHighlighted
  127. | BgTabReplaced
  128. | BgTabZoomChanged
  129. derive instance genBackgroundEvent :: Generic BackgroundEvent _
  130. instance showBackgroundEvent :: Show BackgroundEvent where
  131. show = genericShow
  132. data SidebarEvent
  133. = SbTabDeleted TabId
  134. | SbTabActived TabId
  135. | SbTabCreated
  136. | SbTabMoved TabId Int
  137. | SbTabDetached
  138. | SbGroupCreated
  139. | SbGroupDeleted
  140. | SbGroupRenamed
  141. | SbHasWindowId WindowId
  142. derive instance genSidebarEvent :: Generic SidebarEvent _
  143. instance showSidebarEvent :: Show SidebarEvent where
  144. show = genericShow