@@ -28,6 +28,7 @@ import qualified Data.JSString as JSS
2828import qualified Data.JSString.Text as JSS
2929import qualified Data.List as List
3030import qualified Data.Map.Strict as Map
31+ import qualified Data.Maybe as M
3132import Data.Monoid (Endo (Endo ), appEndo )
3233import Data.Proxy
3334import qualified Data.Set as Set
@@ -97,7 +98,7 @@ utc2unix :: UTCTime -> Int
9798utc2unix x = ceiling (realToFrac (utcTimeToPOSIXSeconds x) :: Double )
9899
99100bodyElement4 :: forall t m . (SupportsServantReflex t m , MonadFix m , MonadIO m , MonadHold t m , PostBuild t m , DomBuilder t m , Adjustable t m , DomBuilderSpace m ~ GhcjsDomSpace ) => m ()
100- bodyElement4 = do
101+ bodyElement4 = mdo
101102 dynLoc <- browserHistoryWith getLocationUri
102103 let dynFrag = decodeFrag . T. pack . uriFragment <$> dynLoc
103104
@@ -139,49 +140,7 @@ bodyElement4 = do
139140 text " )"
140141
141142 -- search box
142- searchInputE <- elAttr " div" (" class" =: " item search right clearfix" ) $ do
143- divClass " text" $ text " Package Search"
144- sVal0 <- inputElement $ def & inputElementConfig_elementConfig . elementConfig_initialAttributes .~ fold
145- [" class" =: " input-search" ," placeholder" =: " search..." ]
146- debounce 0.1 $ _inputElement_input sVal0
147-
148- let
149- dynPackagesJss = V. toList . fmap (JSS. textToJSString . pkgNToText) <$> dynPackages0
150- calcMatches pkgs sJss =
151- if JSS. length sJss < 3
152- then []
153- else matches' pkgs sJss
154- where
155- matches' p sJ
156- | JSS. isInfixOf " ^" sJ = filter (JSS. isPrefixOf (JSS. dropWhile (== ' ^' ) sJ)) p
157- | JSS. isInfixOf " $" sJ = filter (JSS. isSuffixOf (JSS. dropWhileEnd (== ' $' ) sJ)) p
158- | otherwise = filter (JSS. isInfixOf sJ) p
159- exactMatches pkgs' sJss = List. partition (== (JSS. dropWhileEnd (== ' $' ) sJss)) pkgs'
160- matchesE = calcMatches <$> current dynPackagesJss <@> (JSS. textToJSString <$> searchInputE)
161- dynMatches <- holdDyn [] matchesE
162- dynSearch <- holdDyn " " (JSS. textToJSString <$> searchInputE)
163- let
164- exactDyn = splitDynPure $ zipDynWith exactMatches dynMatches dynSearch
165- matchesMapDyn = Map. fromList . fmap (\ p -> (JSS. textFromJSString p,() )) <$> (snd exactDyn)
166- exactMapDyn = Map. fromList . fmap (\ p -> (JSS. textFromJSString p,() )) <$> (fst exactDyn)
167- -- matchesMapDyn <- holdDyn Map.empty matchesMapE
168- _ <- el " ul" $ do
169- listWithKey exactMapDyn $ \ eId _ ->
170- el " li" $ elAttr " a" (" href" =: (" #/package/" <> eId)) $ el " strong" $ text eId
171- listWithKey matchesMapDyn $ \ pId _ ->
172- el " li" $ elAttr " a" (" href" =: (" #/package/" <> pId)) $ do
173- let
174- tbFront txt txtS = T. breakOn txtS txt
175- tbEnd txt txtS = T. breakOnEnd txtS txt
176- breakText = tbFront pId . JSS. textFromJSString <$> dynSearch
177- (dynFirstT,dynSndT) = splitDynPure breakText
178- breakSndText = zipDynWith tbEnd dynSndT (JSS. textFromJSString <$> dynSearch)
179- (dynMidT,dynEndT) = splitDynPure breakSndText
180- dynText dynFirstT
181- el " strong" $ dynText dynMidT
182- dynText dynEndT
183-
184-
143+ _ <- searchBoxWidget dynPackages0
185144 el " hr" blank
186145
187146 _ <- dyn $ dynFrag >>= \ case
@@ -427,7 +386,7 @@ bodyElement4 = do
427386 addTag0 <- elClass " form" " form" $ do
428387 el " p" $ text " Tag : "
429388 tagName <- textInput iCfg
430- tagButton <- button_ " Add Tag"
389+ tagButton <- clickElement_ " button " " Add Tag"
431390 let tVal = _textInput_value tagName
432391 evAdd = (tagPromptlyDyn tVal tagButton)
433392 addTagN <- holdDyn " " evAdd
@@ -777,11 +736,72 @@ pkgTagList m = Map.fromListWith (List.++) $ do
777736joinE :: forall t m a . (Reflex t , MonadHold t m ) => Event t (Event t a ) -> m (Event t a )
778737joinE = fmap switch . hold never
779738
780- button_ :: forall t m . (DomBuilder t m , PostBuild t m ) => T. Text -> m (Event t () )
781- button_ t = do
739+ clickElement_ :: forall t m . (DomBuilder t m , PostBuild t m ) => T. Text - > T. Text -> m (Event t () )
740+ clickElement_ elm t = do
782741 let cfg = (def :: ElementConfig EventResult t (DomBuilderSpace m ))
783742 & elementConfig_eventSpec %~ addEventSpecFlags (Proxy :: Proxy (DomBuilderSpace m )) Click (\ _ -> preventDefault)
784- (e, _) <- element " button " cfg $ text t
743+ (e, _) <- element elm cfg $ text t
785744 pure $ domEvent Click e
786745
746+ stripSearch :: JSS. JSString -> JSS. JSString
747+ stripSearch sJ
748+ | Just sJ' <- JSS. stripPrefix " ^" sJ = sJ'
749+ | Just sJ' <- JSS. stripSuffix " $" sJ = sJ'
750+ | otherwise = sJ
751+
752+ filterBySearchBox :: [JSS. JSString ] -> JSS. JSString -> [JSS. JSString ]
753+ filterBySearchBox pkgs sJ
754+ | JSS. isInfixOf " ^" sJ = filter (JSS. isPrefixOf (stripSearch sJ)) pkgs
755+ | JSS. isInfixOf " $" sJ = filter (JSS. isSuffixOf (stripSearch sJ)) pkgs
756+ | otherwise = filter (JSS. isInfixOf (stripSearch sJ))pkgs
757+
758+ splitInfixPkg :: JSS. JSString -> JSS. JSString -> (T. Text , T. Text , T. Text )
759+ splitInfixPkg stripSJ pkg = (frontT, midT, backT)
760+ where
761+ textS = JSS. textFromJSString stripSJ
762+ (frontT, reminderT) = T. breakOn textS (JSS. textFromJSString pkg)
763+ (midT, backT) = T. breakOnEnd textS reminderT
764+
765+ calcMatchesNew :: [JSS. JSString ] -> JSS. JSString -> Matches
766+ calcMatchesNew pkgs sJss =
767+ if JSS. length sJss < 3
768+ then matchesEmpty
769+ else Matches { matchesInput = textS, matchesExact = exactMap, matchesInfix = othersMap}
770+ where
771+ textS = JSS. textFromJSString sJss
772+ stripSJ = stripSearch sJss
773+ (exactPkg, infixPkg) = List. partition (== stripSJ) pkgs
774+ exactMap = (Map. fromList . fmap (\ p -> (JSS. textFromJSString p,() ))) exactPkg
775+ othersMap = (Map. fromList . fmap (\ p -> (JSS. textFromJSString p, splitInfixPkg stripSJ p))) (filterBySearchBox infixPkg sJss)
776+
777+ searchBoxWidget :: forall t m . (SupportsServantReflex t m , MonadFix m , MonadIO m , MonadHold t m , PostBuild t m , DomBuilder t m , Adjustable t m , DomBuilderSpace m ~ GhcjsDomSpace )
778+ => Dynamic t (Vector PkgN )
779+ -> m ()
780+ searchBoxWidget dynPkgs0 = mdo
781+ searchInputE <- elAttr " div" (" class" =: " item search right clearfix" ) $ do
782+ divClass " text" $ text " Package Search"
783+ sVal0 <- inputElement $ def & inputElementConfig_elementConfig . elementConfig_initialAttributes .~ fold [" class" =: " input-search" ," placeholder" =: " search..." ]
784+ & inputElementConfig_setValue .~ clickPkgE
785+ debounce 0.1 $ leftmost [clickPkgE, (_inputElement_input sVal0)]
786+ let
787+ dynPackagesJss = V. toList . fmap (JSS. textToJSString . pkgNToText) <$> dynPkgs0
788+ matchesE = calcMatchesNew <$> current dynPackagesJss <@> (JSS. textToJSString <$> searchInputE)
789+ matchesDyn <- holdDyn matchesEmpty matchesE
790+ clickPkgE <- searchResultWidget matchesDyn
791+ pure ()
787792
793+ searchResultWidget :: forall t m . (MonadFix m , MonadHold t m , PostBuild t m , DomBuilder t m )
794+ => Dynamic t Matches
795+ -> m (Event t T. Text )
796+ searchResultWidget mDyn =
797+ el " ul" $ do
798+ exactE <- listViewWithKey (matchesExact <$> mDyn) $ \ eId _ -> do
799+ (e, _) <- element " li" def $ elAttr " a" (" href" =: (" #/package/" <> eId)) $ el " strong" $ text eId
800+ pure $ domEvent Click e
801+ otherE <- listViewWithKey (matchesInfix <$> mDyn) $ \ pId txt -> do
802+ (e, _) <- element " li" def $ elAttr " a" (" href" =: (" #/package/" <> pId)) $ do
803+ dynText . fmap (^. _1) $ txt
804+ el " strong" $ dynText . fmap (^. _2) $ txt
805+ dynText . fmap (^. _3) $ txt
806+ pure $ domEvent Click e
807+ pure $ " " <$ leftmost [exactE, otherE]
0 commit comments