[NGRAMS] grouping

parent 422a0c80
module Gargantext.Pages.Corpus.Tabs.Ngrams.NgramsTable where module Gargantext.Pages.Corpus.Tabs.Ngrams.NgramsTable where
import Control.Monad.State (class MonadState, execState)
import Data.Argonaut (class DecodeJson, decodeJson, (.?), (.??)) import Data.Argonaut (class DecodeJson, decodeJson, (.?), (.??))
import Data.Array (filter, toUnfoldable) import Data.Array (filter, toUnfoldable)
import Data.Either (Either(..)) import Data.Either (Either(..))
import Data.Foldable
import Data.FoldableWithIndex
import Data.FunctorWithIndex import Data.FunctorWithIndex
import Data.Newtype (class Newtype, unwrap) import Data.Newtype (class Newtype, unwrap)
import Data.Lens (Lens', Prism', lens, over, prism, (^..)) import Data.Lens (Lens', Prism', Iso', lens, over, prism, (^.), (^..), (%~), (.=), use, (<>~))
import Data.Lens.Common (_Just)
import Data.Lens.At (class At, at) import Data.Lens.At (class At, at)
import Data.Lens.Index (class Index, ix) import Data.Lens.Index (class Index, ix)
import Data.Lens.Fold (folded) import Data.Lens.Fold (folded)
import Data.Lens.Getter (to) import Data.Lens.Getter (to)
import Data.Lens.Record (prop)
import Data.Lens.Iso (re) import Data.Lens.Iso (re)
import Data.Lens.Iso.Newtype (_Newtype) import Data.Lens.Iso.Newtype (_Newtype)
import Data.List (List) import Data.List (List)
...@@ -18,9 +23,11 @@ import Data.List as List ...@@ -18,9 +23,11 @@ import Data.List as List
import Data.Map (Map) import Data.Map (Map)
import Data.Map as Map import Data.Map as Map
import Data.Maybe (Maybe(..), maybe) import Data.Maybe (Maybe(..), maybe)
import Data.Traversable (traverse) import Data.Traversable (class Traversable, traverse, traverse_, sequence)
import Data.TraversableWithIndex (class TraversableWithIndex, traverseWithIndex)
import Data.Set (Set) import Data.Set (Set)
import Data.Set as Set import Data.Set as Set
import Data.Symbol (SProxy(..))
import Data.Tuple (Tuple(..), uncurry) import Data.Tuple (Tuple(..), uncurry)
import Data.Void (Void) import Data.Void (Void)
import Data.Unit (Unit) import Data.Unit (Unit)
...@@ -58,22 +65,29 @@ newtype NgramsElement = NgramsElement ...@@ -58,22 +65,29 @@ newtype NgramsElement = NgramsElement
{ ngrams :: NgramsTerm { ngrams :: NgramsTerm
, list :: TermList , list :: TermList
, occurrences :: Int , occurrences :: Int
, root :: Maybe NgramsTerm , parent :: Maybe NgramsTerm
, children :: Set NgramsTerm , children :: Set NgramsTerm
} }
_parent = prop (SProxy :: SProxy "parent")
_children :: forall row. Lens' { children :: Set NgramsTerm | row } (Set NgramsTerm)
_children = prop (SProxy :: SProxy "children")
derive instance newtypeNgramsElement :: Newtype NgramsElement _ derive instance newtypeNgramsElement :: Newtype NgramsElement _
_NgramsElement :: Iso' NgramsElement _
_NgramsElement = _Newtype
instance decodeJsonNgramsElement :: DecodeJson NgramsElement where instance decodeJsonNgramsElement :: DecodeJson NgramsElement where
decodeJson json = do decodeJson json = do
obj <- decodeJson json obj <- decodeJson json
ngrams <- obj .? "ngrams" ngrams <- obj .? "ngrams"
list <- obj .? "list" list <- obj .? "list"
occurrences <- obj .? "occurrences" occurrences <- obj .? "occurrences"
root <- obj .?? "root" parent <- obj .?? "parent"
children' <- obj .? "children" children' <- obj .? "children"
let children = Set.fromFoldable (children' :: Array NgramsTerm) let children = Set.fromFoldable (children' :: Array NgramsTerm)
pure $ NgramsElement {ngrams, list, occurrences, root, children} pure $ NgramsElement {ngrams, list, occurrences, parent, children}
-- type NgramsTable = Array (NTree NgramsElement) -- type NgramsTable = Array (NTree NgramsElement)
-- type NgramsTable = Array NgramsElement -- type NgramsTable = Array NgramsElement
...@@ -81,11 +95,14 @@ newtype NgramsTable = NgramsTable (Map NgramsTerm NgramsElement) ...@@ -81,11 +95,14 @@ newtype NgramsTable = NgramsTable (Map NgramsTerm NgramsElement)
derive instance newtypeNgramsTable :: Newtype NgramsTable _ derive instance newtypeNgramsTable :: Newtype NgramsTable _
_NgramsTable :: Iso' NgramsTable (Map NgramsTerm NgramsElement)
_NgramsTable = _Newtype
instance indexNgramsTable :: Index NgramsTable String NgramsElement where instance indexNgramsTable :: Index NgramsTable String NgramsElement where
ix k = _Newtype <<< ix k ix k = _NgramsTable <<< ix k
instance atNgramsTable :: At NgramsTable String NgramsElement where instance atNgramsTable :: At NgramsTable String NgramsElement where
at k = _Newtype <<< at k at k = _NgramsTable <<< at k
instance decodeJsonNgramsTable :: DecodeJson NgramsTable where instance decodeJsonNgramsTable :: DecodeJson NgramsTable where
decodeJson json = do decodeJson json = do
...@@ -121,6 +138,8 @@ applyReplace (Replace { old, new }) a ...@@ -121,6 +138,8 @@ applyReplace (Replace { old, new }) a
| a == old = new | a == old = new
| otherwise = a | otherwise = a
-- Representing a PatchSet as `Map a Boolean` would have the advantage
-- of enforcing rem and add to be disjoint.
newtype PatchSet a = PatchSet newtype PatchSet a = PatchSet
{ rem :: Set a { rem :: Set a
, add :: Set a , add :: Set a
...@@ -138,6 +157,11 @@ instance monoidPatchSet :: Ord a => Monoid (PatchSet a) where ...@@ -138,6 +157,11 @@ instance monoidPatchSet :: Ord a => Monoid (PatchSet a) where
applyPatchSet :: forall a. Ord a => PatchSet a -> Set a -> Set a applyPatchSet :: forall a. Ord a => PatchSet a -> Set a -> Set a
applyPatchSet (PatchSet p) s = Set.difference s p.rem <> p.add applyPatchSet (PatchSet p) s = Set.difference s p.rem <> p.add
patchSetFromMap :: forall a. Ord a => Map a Boolean -> PatchSet a
patchSetFromMap m = PatchSet { rem: Map.keys (Map.filter not m)
, add: Map.keys (Map.filter identity m) }
-- TODO Map.partition would be nice here
newtype NgramsPatch = NgramsPatch newtype NgramsPatch = NgramsPatch
{ patch_children :: PatchSet NgramsTerm { patch_children :: PatchSet NgramsTerm
, patch_list :: Replace TermList , patch_list :: Replace TermList
...@@ -157,8 +181,7 @@ applyNgramsPatch (NgramsPatch p) (NgramsElement e) = NgramsElement ...@@ -157,8 +181,7 @@ applyNgramsPatch (NgramsPatch p) (NgramsElement e) = NgramsElement
{ ngrams: e.ngrams { ngrams: e.ngrams
, list: applyReplace p.patch_list e.list , list: applyReplace p.patch_list e.list
, occurrences: e.occurrences -- TODO: is this correct ? , occurrences: e.occurrences -- TODO: is this correct ?
, root: e.root -- TODO: is this correct ? , parent: e.parent
-- See ROOT-UPDATE
, children: applyPatchSet p.patch_children e.children , children: applyPatchSet p.patch_children e.children
} }
...@@ -170,6 +193,34 @@ instance semigroupPatchMap :: (Ord k, Semigroup p) => Semigroup (PatchMap k p) w ...@@ -170,6 +193,34 @@ instance semigroupPatchMap :: (Ord k, Semigroup p) => Semigroup (PatchMap k p) w
instance monoidPatchMap :: (Ord k, Semigroup p) => Monoid (PatchMap k p) where instance monoidPatchMap :: (Ord k, Semigroup p) => Monoid (PatchMap k p) where
mempty = PatchMap Map.empty mempty = PatchMap Map.empty
derive instance newtypePatchMap :: Newtype (PatchMap k p) _
_PatchMap :: forall k p. Iso' (PatchMap k p) (Map k p)
_PatchMap = _Newtype
instance functorPatchMap :: Functor (PatchMap k) where
map f (PatchMap m) = PatchMap (map f m)
instance functorWithIndexPatchMap :: FunctorWithIndex k (PatchMap k) where
mapWithIndex f (PatchMap m) = PatchMap (mapWithIndex f m)
instance foldlablePatchMap :: Foldable (PatchMap k) where
foldr f z (PatchMap m) = foldr f z m
foldl f z (PatchMap m) = foldl f z m
foldMap f (PatchMap m) = foldMap f m
instance foldlableWithIndexPatchMap :: FoldableWithIndex k (PatchMap k) where
foldrWithIndex f z (PatchMap m) = foldrWithIndex f z m
foldlWithIndex f z (PatchMap m) = foldlWithIndex f z m
foldMapWithIndex f (PatchMap m) = foldMapWithIndex f m
instance traversablePatchMap :: Traversable (PatchMap k) where
traverse f (PatchMap m) = PatchMap <$> traverse f m
sequence (PatchMap m) = PatchMap <$> sequence m
instance traversableWithIndexPatchMap :: TraversableWithIndex k (PatchMap k) where
traverseWithIndex f (PatchMap m) = PatchMap <$> traverseWithIndex f m
applyPatchMap :: forall k p v. Ord k => (p -> v -> v) -> PatchMap k p -> Map k v -> Map k v applyPatchMap :: forall k p v. Ord k => (p -> v -> v) -> PatchMap k p -> Map k v -> Map k v
applyPatchMap applyPatchValue (PatchMap p) = mapWithIndex f applyPatchMap applyPatchValue (PatchMap p) = mapWithIndex f
where where
...@@ -180,22 +231,48 @@ applyPatchMap applyPatchValue (PatchMap p) = mapWithIndex f ...@@ -180,22 +231,48 @@ applyPatchMap applyPatchValue (PatchMap p) = mapWithIndex f
type NgramsTablePatch = PatchMap NgramsTerm NgramsPatch type NgramsTablePatch = PatchMap NgramsTerm NgramsPatch
type ReParent a = forall m. MonadState NgramsTable m => a -> m Unit
reParent :: Maybe NgramsTerm -> ReParent NgramsTerm
reParent parent child =
at child <<< _Just <<< _NgramsElement <<< _parent .= parent
-- reParentNgramsPatch :: NgramsTerm -> ReParent NgramsPatch
-- ^ GHC would have accepted this type. Here reParentNgramsPatch checks but
-- not its usage in reParentNgramsTablePatch.
reParentNgramsPatch :: forall m. MonadState NgramsTable m
=> NgramsTerm -> NgramsPatch -> m Unit
reParentNgramsPatch parent (NgramsPatch {patch_children: PatchSet {rem, add}}) = do
traverse_ (reParent Nothing) rem
traverse_ (reParent $ Just parent) add
reParentNgramsTablePatch :: ReParent NgramsTablePatch
reParentNgramsTablePatch = void <<< traverseWithIndex reParentNgramsPatch
applyNgramsTablePatch :: NgramsTablePatch -> NgramsTable -> NgramsTable applyNgramsTablePatch :: NgramsTablePatch -> NgramsTable -> NgramsTable
applyNgramsTablePatch p (NgramsTable m) = applyNgramsTablePatch p (NgramsTable m) =
NgramsTable (applyPatchMap applyNgramsPatch p m) execState (reParentNgramsTablePatch p) $
NgramsTable $ applyPatchMap applyNgramsPatch p m
-- TODO: update the .root fields... -- TODO: update the .root fields...
-- See ROOT-UPDATE -- See ROOT-UPDATE
type State = type State =
{ ngramsTablePatch :: NgramsTablePatch { ngramsTablePatch :: NgramsTablePatch
, ngramsParent :: Maybe NgramsTerm -- Nothing means we are not currently grouping terms
, ngramsChildren :: Set NgramsTerm -- Used only when grouping, this is the set
-- of future children of `ngramsParent`.
, searchQuery :: String , searchQuery :: String
, termListFilter :: Maybe TermList -- Nothing means all , termListFilter :: Maybe TermList -- Nothing means all
, termTypeFilter :: Maybe TermType -- Nothing means all , termTypeFilter :: Maybe TermType -- Nothing means all
} }
_ngramsChildren = prop (SProxy :: SProxy "ngramsChildren")
initialState :: forall props. props -> State initialState :: forall props. props -> State
initialState _ = initialState _ =
{ ngramsTablePatch: mempty { ngramsTablePatch: mempty
, ngramsParent: Nothing
, ngramsChildren: mempty
, searchQuery: "" , searchQuery: ""
, termListFilter: Nothing , termListFilter: Nothing
, termTypeFilter: Nothing , termTypeFilter: Nothing
...@@ -203,7 +280,16 @@ initialState _ = ...@@ -203,7 +280,16 @@ initialState _ =
data Action data Action
= SetTermListItem NgramsTerm (Replace TermList) = SetTermListItem NgramsTerm (Replace TermList)
| AddTermChildren { parent :: NgramsTerm, child :: NgramsTerm } | SetParentResetChildren (Maybe NgramsTerm)
-- ^ This sets `ngramsParent` and resets `ngramsChildren`.
| ToggleChild Boolean NgramsTerm
-- ^ Toggles the NgramsTerm in the `PatchSet` `ngramsChildren`.
-- If the `Boolean` is `true` it means we want to add it if it is not here,
-- if it is `false` it is meant to be removed if not here.
| AddTermChildren -- NgramsTable
-- ^ The NgramsTable argument is here as a cache of `ngramsTablePatch`
-- applied to `initTable`.
-- TODO more docs
| SetTermListFilter (Maybe TermList) | SetTermListFilter (Maybe TermList)
| SetTermTypeFilter (Maybe TermType) | SetTermTypeFilter (Maybe TermType)
| SetSearchQuery String | SetSearchQuery String
...@@ -212,8 +298,14 @@ data Mode = Authors | Sources | Terms | Trash ...@@ -212,8 +298,14 @@ data Mode = Authors | Sources | Terms | Trash
type Dispatch = Action -> Effect Unit type Dispatch = Action -> Effect Unit
tableContainer :: {searchQuery :: String, dispatch :: Dispatch} -> T.TableContainerProps -> Array ReactElement tableContainer :: { searchQuery :: String
tableContainer {searchQuery, dispatch} props = , dispatch :: Dispatch
, ngramsParent :: Maybe NgramsTerm
, ngramsChildren :: Map NgramsTerm Boolean
, ngramsTable :: NgramsTable
}
-> T.TableContainerProps -> Array ReactElement
tableContainer {searchQuery, dispatch, ngramsParent, ngramsChildren, ngramsTable: ngramsTableCache} props =
[ div [className "container-fluid"] [ div [className "container-fluid"]
[ div [className "jumbotron1"] [ div [className "jumbotron1"]
[ div [className "row"] [ div [className "row"]
...@@ -262,6 +354,23 @@ tableContainer {searchQuery, dispatch} props = ...@@ -262,6 +354,23 @@ tableContainer {searchQuery, dispatch} props =
] ]
] ]
] ]
, div [] (maybe [] (\ngrams ->
let
ngramsTable =
ngramsTableCache # at ngrams
<<< _Just
<<< _NgramsElement
<<< _children
%~ applyPatchSet (patchSetFromMap ngramsChildren)
ngramsClick child
| child == ngrams = Nothing
| otherwise = Just $ dispatch $ ToggleChild false child
in
[ p[] [text $ "Editing " <> ngrams]
, renderNgramsTree { ngramsTable, ngrams, ngramsStyle: [], ngramsClick }
, button [className "btn btn-primary", onClick $ const $ dispatch $ AddTermChildren] [text "Save"]
, button [className "btn btn-secondary", onClick $ const $ dispatch $ SetParentResetChildren Nothing] [text "Cancel"]
]) ngramsParent)
, div [ _id "terms_table", className "panel-body" ] , div [ _id "terms_table", className "panel-body" ]
[ table [ className "table able table-bordered" ] [ table [ className "table able table-bordered" ]
[ thead [ className "tableHeader table-bordered"] [props.tableHead] [ thead [ className "tableHeader table-bordered"] [props.tableHead]
...@@ -277,27 +386,42 @@ tableContainer {searchQuery, dispatch} props = ...@@ -277,27 +386,42 @@ tableContainer {searchQuery, dispatch} props =
commitPatch :: NgramsTablePatch -> StateCoTransformer State Unit commitPatch :: NgramsTablePatch -> StateCoTransformer State Unit
commitPatch pt = modifyState_ $ \s -> s { ngramsTablePatch = pt <> s.ngramsTablePatch } commitPatch pt = modifyState_ $ \s -> s { ngramsTablePatch = pt <> s.ngramsTablePatch }
toggleMap :: forall a. a -> Maybe a -> Maybe a
toggleMap _ (Just _) = Nothing
toggleMap b Nothing = Just b
ngramsTableSpec' :: Spec State Props' Action ngramsTableSpec' :: Spec State Props' Action
ngramsTableSpec' = simpleSpec performAction render ngramsTableSpec' = simpleSpec performAction render
where where
setParentResetChildren :: Maybe NgramsTerm -> State -> State
setParentResetChildren p = _ { ngramsParent = p, ngramsChildren = mempty }
performAction :: PerformAction State Props' Action performAction :: PerformAction State Props' Action
performAction (SetTermListFilter c) _ _ = modifyState_ $ _ { termListFilter = c } performAction (SetTermListFilter c) _ _ = modifyState_ $ _ { termListFilter = c }
performAction (SetTermTypeFilter c) _ _ = modifyState_ $ _ { termTypeFilter = c } performAction (SetTermTypeFilter c) _ _ = modifyState_ $ _ { termTypeFilter = c }
performAction (SetSearchQuery s) _ _ = modifyState_ $ _ { searchQuery = s } performAction (SetSearchQuery s) _ _ = modifyState_ $ _ { searchQuery = s }
performAction (SetParentResetChildren p) _ _ =
modifyState_ $ setParentResetChildren p
performAction (ToggleChild b c) _ _ =
modifyState_ $ _ngramsChildren <<< at c %~ toggleMap b
performAction (SetTermListItem n pl) _ _ = commitPatch pt performAction (SetTermListItem n pl) _ _ = commitPatch pt
where where
pe = NgramsPatch { patch_list: pl, patch_children: mempty } pe = NgramsPatch { patch_list: pl, patch_children: mempty }
pt = PatchMap $ Map.singleton n pe pt = PatchMap $ Map.singleton n pe
performAction (AddTermChildren { parent, child {- , child_root, parent_root -} }) _ _ = commitPatch pt performAction AddTermChildren _ {ngramsParent: Nothing} =
-- impossible but harmless
pure unit
performAction AddTermChildren _
{ ngramsParent: Just parent
, ngramsChildren
, ngramsTablePatch
} = do
modifyState_ $ setParentResetChildren Nothing
commitPatch pt
where where
pc = PatchSet { rem: mempty, add: Set.singleton child } pc = patchSetFromMap ngramsChildren
pe = NgramsPatch { patch_list: mempty, patch_children: pc } pe = NgramsPatch { patch_list: mempty, patch_children: pc }
-- pr = NgramsPatch { patch_list: mempty
-- , patch_children: mempty
-- , patch_root: replace child_root parent_root
-- }
pt = PatchMap $ Map.fromFoldable [Tuple parent pe] pt = PatchMap $ Map.fromFoldable [Tuple parent pe]
-- ,Tuple child pr]
-- TODO ROOT-UPDATE -- TODO ROOT-UPDATE
-- patch the root of the child to be equal to the root of the parent. -- patch the root of the child to be equal to the root of the parent.
...@@ -305,11 +429,12 @@ ngramsTableSpec' = simpleSpec performAction render ...@@ -305,11 +429,12 @@ ngramsTableSpec' = simpleSpec performAction render
render dispatch { path: {nodeId} render dispatch { path: {nodeId}
, loaded: initTable , loaded: initTable
, dispatch: loaderDispatch } , dispatch: loaderDispatch }
{ ngramsTablePatch, searchQuery } _children = { ngramsTablePatch, ngramsParent, ngramsChildren, searchQuery }
_reactChildren =
[ T.tableElt [ T.tableElt
{ rows { rows
, setParams: \params -> loaderDispatch (Loader.SetPath {nodeId, params}) , setParams: \params -> loaderDispatch (Loader.SetPath {nodeId, params})
, container: tableContainer {searchQuery, dispatch} , container: tableContainer {searchQuery, dispatch, ngramsParent, ngramsChildren, ngramsTable}
, colNames: , colNames:
T.ColumnName <$> T.ColumnName <$>
[ "Graph" [ "Graph"
...@@ -321,22 +446,34 @@ ngramsTableSpec' = simpleSpec performAction render ...@@ -321,22 +446,34 @@ ngramsTableSpec' = simpleSpec performAction render
} }
] ]
where where
rows = ngramsTable =
case applyNgramsTablePatch ngramsTablePatch <$> initTable of case applyNgramsTablePatch ngramsTablePatch <$> initTable of
Nothing -> [] -- or an error Nothing -> NgramsTable mempty
Just t@(NgramsTable table) -> Just t -> t
convertRow t <$> Map.toUnfoldable (Map.filter isRoot table) rows = convertRow <$> Map.toUnfoldable (Map.filter displayRow (ngramsTable ^. _NgramsTable))
isRoot (NgramsElement e) = e.root == Nothing isRoot (NgramsElement e) = e.parent == Nothing
convertRow table (Tuple ngrams (NgramsElement { occurrences, list })) = -- TODO: There is a missing case where we display a row that we should not.
-- Assumptions:
-- * cats -> cat -> animal
-- * We are editing cats: ngramsParent == Just "cats"
-- * animal should not be listed since this would create a cycle!
displayRow e@(NgramsElement {ngrams, children, parent}) =
isRoot e
-- ^ Display only nodes with parents
&& (ngramsChildren ^. at ngrams /= Just true)
-- ^ and which are not scheduled to be added already.
&& (case ngramsParent of
Just p ->
ngrams /= p &&
-- ^ and which is not the node being currently edited.
not (Set.member p children)
-- ^ ... or one of its children.
Nothing -> true)
|| -- Unless they are scheduled to be removed.
(ngramsChildren ^. at ngrams == Just false)
convertRow (Tuple ngrams (NgramsElement { occurrences, list })) =
{ row: { row:
let renderNgramsItem { ngramsTable, ngrams, occurrences, ngramsParent, termList: list, dispatch }
setTermList Keep = do
logs "setTermList Keep"
pure unit
setTermList rep@(Replace {old,new}) = do
logs $ Tuple "setTermList" (Tuple old new)
dispatch $ SetTermListItem ngrams rep in
renderNgramsItem { table, ngrams, occurrences, termList: list, setTermList }
, delete: false , delete: false
} }
...@@ -367,39 +504,66 @@ ngramsTableSpec = simpleSpec defaultPerformAction render ...@@ -367,39 +504,66 @@ ngramsTableSpec = simpleSpec defaultPerformAction render
render _ {path: nodeId} _ _ = render _ {path: nodeId} _ _ =
-- TODO: ignored mode, ignored loaded: corpusInfo -- TODO: ignored mode, ignored loaded: corpusInfo
[ ngramsLoader { path: initialPageParams nodeId [ ngramsLoader { path: initialPageParams nodeId
, component: createClass "Layout" ngramsTableSpec' initialState , component: createClass "NgramsTableLayout" ngramsTableSpec' initialState
} ] } ]
tree :: NgramsTable -> DOM.Props -> NgramsTerm -> ReactElement tree :: { ngramsTable :: NgramsTable
tree table props label = , ngramsStyle :: Array DOM.Props
, ngramsClick :: NgramsTerm -> Maybe (Effect Unit)
} -> NgramsTerm -> ReactElement
tree params@{ngramsTable, ngramsStyle, ngramsClick} label =
li [ style {width : "100%"} ] li [ style {width : "100%"} ]
[ i (gray <> [className $ "fas fa-caret-" <> if open then "down" else "right"]) [] [ i icon []
, span [props] [text $ " " <> label] , tag [text $ " " <> label]
, forest table props cs , forest cs
] ]
where where
tag =
case ngramsClick label of
Just effect ->
a (ngramsStyle <> [onClick $ const effect])
Nothing ->
span ngramsStyle
leaf = List.null cs leaf = List.null cs
icon = gray <> [className $ "fas fa-caret-" <> if open then "down" else "right"]
open = not leaf || false {- TODO -} open = not leaf || false {- TODO -}
gray = if leaf then [style {color: "#adb5bd"}] else [] gray = if leaf then [style {color: "#adb5bd"}] else []
cs = table ^.. ix label <<< _Newtype <<< to _.children <<< folded cs = ngramsTable ^.. ix label <<< _NgramsElement <<< _children <<< folded
forest :: NgramsTable -> DOM.Props -> List NgramsTerm -> ReactElement forest = ul [] <<< map (tree params) <<< List.toUnfoldable
forest table props = ul [] <<< map (tree table props) <<< List.toUnfoldable
renderNgramsTree :: { ngrams :: NgramsTerm
, ngramsTable :: NgramsTable
, ngramsStyle :: Array DOM.Props
, ngramsClick :: NgramsTerm -> Maybe (Effect Unit)
} -> ReactElement
renderNgramsTree { ngramsTable, ngrams, ngramsStyle, ngramsClick } =
ul [] [
span [className "tree"] [tree {ngramsTable, ngramsStyle, ngramsClick} ngrams]
]
renderNgramsItem :: { table :: NgramsTable renderNgramsItem :: { ngrams :: NgramsTerm
, ngrams :: String , ngramsTable :: NgramsTable
, occurrences :: Int , occurrences :: Int
, termList :: TermList , termList :: TermList
, setTermList :: Replace TermList -> Effect Unit , ngramsParent :: Maybe NgramsTerm
, dispatch :: Action -> Effect Unit
} -> Array ReactElement } -> Array ReactElement
renderNgramsItem { table, ngrams, occurrences, termList, setTermList } = renderNgramsItem { ngramsTable, ngrams, occurrences, termList, ngramsParent, dispatch } =
[ checkbox GraphTerm [ checkbox GraphTerm
, checkbox StopTerm , checkbox StopTerm
, ul [] [span [className "tree"] [tree table (termStyle termList) ngrams]] , if ngramsParent == Nothing
then renderNgramsTree { ngramsTable, ngrams, ngramsStyle, ngramsClick }
else
a [onClick $ const $ dispatch $ ToggleChild true ngrams]
[ i [className "fas fa-plus"] []
, span ngramsStyle [text $ " " <> ngrams]
]
, text $ show occurrences , text $ show occurrences
] ]
where where
ngramsStyle = [termStyle termList]
ngramsClick = Just <<< dispatch <<< SetParentResetChildren <<< Just
checkbox termList' = checkbox termList' =
let chkd = termList == termList' let chkd = termList == termList'
termList'' = if chkd then CandidateTerm else termList' termList'' = if chkd then CandidateTerm else termList'
...@@ -412,6 +576,9 @@ renderNgramsItem { table, ngrams, occurrences, termList, setTermList } = ...@@ -412,6 +576,9 @@ renderNgramsItem { table, ngrams, occurrences, termList, setTermList } =
, onChange $ const $ setTermList (replace termList termList'') , onChange $ const $ setTermList (replace termList termList'')
] ]
setTermList Keep = pure unit
setTermList rep@(Replace {old,new}) = dispatch $ SetTermListItem ngrams rep
termStyle :: TermList -> DOM.Props termStyle :: TermList -> DOM.Props
termStyle GraphTerm = style {color: "green"} termStyle GraphTerm = style {color: "green"}
termStyle StopTerm = style {color: "red", textDecoration : "line-through"} termStyle StopTerm = style {color: "red", textDecoration : "line-through"}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment