Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
purescript-gargantext
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
148
Issues
148
List
Board
Labels
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
gargantext
purescript-gargantext
Commits
372acbd0
Commit
372acbd0
authored
Apr 10, 2019
by
Alexandre Delanoë
Browse files
Options
Browse Files
Download
Plain Diff
[MERGE] dev and feature/annotation.
parents
bfe80bc1
7096915f
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
803 additions
and
110 deletions
+803
-110
.gitignore
.gitignore
+2
-2
README.md
README.md
+63
-0
packages.dhall
packages.dhall
+131
-0
psc-package.json
psc-package.json
+2
-0
spago.dhall
spago.dhall
+22
-0
AnnotatedField.purs
src/Gargantext/Components/Annotated/AnnotatedField.purs
+107
-0
ContextMenu.purs
src/Gargantext/Components/ContextMenu/ContextMenu.purs
+113
-0
SimpleItem.purs
src/Gargantext/Components/ContextMenu/SimpleItem.purs
+114
-0
NgramsTable.purs
src/Gargantext/Components/NgramsTable.purs
+1
-0
Document.purs
src/Gargantext/Pages/Corpus/Document.purs
+47
-107
BreakWords.js
src/Gargantext/Text/BreakWords.js
+4
-0
BreakWords.purs
src/Gargantext/Text/BreakWords.purs
+84
-0
Types.purs
src/Gargantext/Types.purs
+8
-0
Utils.purs
src/Gargantext/Utils.purs
+12
-1
Array.js
src/Gargantext/Utils/Array.js
+4
-0
Array.purs
src/Gargantext/Utils/Array.purs
+10
-0
React.purs
src/Gargantext/Utils/React.purs
+14
-0
Regex.js
src/Gargantext/Utils/Regex.js
+8
-0
Regex.purs
src/Gargantext/Utils/Regex.purs
+22
-0
Selection.js
src/Gargantext/Utils/Selection.js
+2
-0
Selection.purs
src/Gargantext/Utils/Selection.purs
+33
-0
No files found.
.gitignore
View file @
372acbd0
...
...
@@ -3,8 +3,8 @@
/.pulp-cache/
/output/
/generated-docs/
/.psc-package/
/.psc*
/.purs*
/.psa*
/dist/css/*map
bundle.js
/.spago
README.md
View file @
372acbd0
...
...
@@ -29,3 +29,66 @@ In one command:
## Note to the contributors
Please follow CONTRIBUTING.md
## Introduction
Making sense of out text isn't actually that hard, but it does require
a little background knowledge to understand.x
### N-grams
N-grams are at the heart of how Gargantext makes sense out of text.
There are two common meanings in the literature for n-gram:
-
a sequence of
`n`
characters
-
a sequence of
`n`
words
Gargantext is focused on words. Here are some example word n-grams;
-
`coffee`
(unigram or 1-gram)
-
`need coffee`
(bigram or 2-gram)
-
`one coffee please`
(trigram or 3-gram)
-
`here is your coffee`
(4-gram)
-
`i need some more coffee`
(5-gram)
N-grams are matched case insensitively and across whole words. Examples:
| Text | N-gram | Matches |
|--------------|--------------|----------------------|
|
`Coffee cup`
|
`coffee`
| YES |
|
`Coffee cup`
|
`off`
| NO, not a whole word |
|
`Coffee cup`
|
`coffee cup`
| YES |
You may read more about n-grams
[
on wikipedia
](
https://en.wikipedia.org/wiki/N-gram
)
.
Gargantext allows you to define n-grams interactively in your browser
and explore the relationships they uncover across a corpus of text.
Various metrics can be applied to n-grams, the most common of which is
the number of times an n-gram appears in a document.
## Glossary
document
: One or more texts comprising a single logical document
field
: A portion of a document, e.g.
`title`
,
`abstract`
,
`body`
corpus
: A collection of documents
n-gram/ngram
: A word or words to be indexed, consisting of
`n`
words.
This technically includes skip-grams, but in the general case
the words will be contiguous.
unigram/1-gram
: A one-word n-gram, e.g.
`cow`
,
`coffee`
bigram/2-gram
: A two-word n-gram, e.g.
`coffee cup`
trigram
: A three-word n-gram, e.g.
`coffee cup holder`
<!-- skip-grams are not yet supported -->
<!-- skip-gram -->
<!-- : An n-gram where the words are not all adjacent -->
<!-- k-skip-n-gram -->
<!-- : An n-gram where the words are at most distance k from each other -->
packages.dhall
0 → 100644
View file @
372acbd0
{-
Welcome to Spacchetti local packages!
Below are instructions for how to edit this file for most use
cases, so that you don't need to know Dhall to use it.
## Warning: Don't Move This Top-Level Comment!
Due to how `dhall format` currently works, this comment's
instructions cannot appear near corresponding sections below
because `dhall format` will delete the comment. However,
it will not delete a top-level comment like this one.
## Use Cases
Most will want to do one or both of these options:
1. Override/Patch a package's dependency
2. Add a package not already in the default package set
This file will continue to work whether you use one or both options.
Instructions for each option are explained below.
### Overriding/Patching a package
Purpose:
- Change a package's dependency to a newer/older release than the
default package set's release
- Use your own modified version of some dependency that may
include new API, changed API, removed API by
using your custom git repo of the library rather than
the package set's repo
Syntax:
Replace the overrides' "{=}" (an empty record) with the following idea
The "//" or "⫽" means "merge these two records and
when they have the same value, use the one on the right:"
-------------------------------
let override =
{ packageName =
upstream.packageName ⫽ { updateEntity1 = "new value", updateEntity2 = "new value" }
, packageName =
upstream.packageName ⫽ { version = "v4.0.0" }
, packageName =
upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" }
}
-------------------------------
Example:
-------------------------------
let overrides =
{ halogen =
upstream.halogen ⫽ { version = "master" }
, halogen-vdom =
upstream.halogen-vdom ⫽ { version = "v4.0.0" }
}
-------------------------------
### Additions
Purpose:
- Add packages that aren't alread included in the default package set
Syntax:
Replace the additions' "{=}" (an empty record) with the following idea:
-------------------------------
let additions =
{ "package-name" =
mkPackage
[ "dependency1"
, "dependency2"
]
"https://example.com/path/to/git/repo.git"
"tag ('v4.0.0') or branch ('master')"
, "package-name" =
mkPackage
[ "dependency1"
, "dependency2"
]
"https://example.com/path/to/git/repo.git"
"tag ('v4.0.0') or branch ('master')"
, etc.
}
-------------------------------
Example:
-------------------------------
let additions =
{ benchotron =
mkPackage
[ "arrays"
, "exists"
, "profunctor"
, "strings"
, "quickcheck"
, "lcg"
, "transformers"
, "foldable-traversable"
, "exceptions"
, "node-fs"
, "node-buffer"
, "node-readline"
, "datetime"
, "now"
]
"https://github.com/hdgarrood/purescript-benchotron.git"
"v7.0.0"
}
-------------------------------
-}
let mkPackage =
https://raw.githubusercontent.com/spacchetti/spacchetti/20181209/src/mkPackage.dhall sha256:8e1c6636f8a089f972b21cde0cef4b33fa36a2e503ad4c77928aabf92d2d4ec9
let upstream =
https://raw.githubusercontent.com/spacchetti/spacchetti/20181209/src/packages.dhall sha256:c63285af67ae74feb2f6eb67521712441928d2726ea10e2040774849ca765027
let overrides =
{ thermite =
mkPackage
[ "aff", "coroutines", "web-dom", "freet", "profunctor-lenses", "react", "react-dom" ]
"https://github.com/np/purescript-thermite.git"
"hide" }
let additions =
{ sequences =
mkPackage
[ "prelude", "unsafe-coerce", "partial", "unfoldable", "lazy", "arrays", "profunctor", "maybe", "tuples", "newtype" ]
"https://github.com/hdgarrood/purescript-sequences.git"
"v2.1.0" }
in upstream ⫽ overrides ⫽ additions
psc-package.json
View file @
372acbd0
...
...
@@ -20,6 +20,8 @@
"random"
,
"affjax"
,
"console"
,
"strings"
,
"string-parsers"
,
"prelude"
]
}
spago.dhall
0 → 100644
View file @
372acbd0
{ name = "gargantext"
, dependencies =
[ "affjax"
, "argonaut"
, "console"
, "css"
, "effect"
, "foldable-traversable"
, "foreign-object"
, "generics-rep"
, "integers"
, "js-timers"
, "prelude"
, "psci-support"
, "random"
, "routing"
, "sequences"
, "strings"
, "thermite"
, "unicode"
, "web-html" ]
, packages = ./packages.dhall }
src/Gargantext/Components/Annotated/AnnotatedField.purs
0 → 100644
View file @
372acbd0
-- | The AnnotatedField Component is for colouring ngrams that appear in a text
-- |
-- | Given a list of ngrams and a text, it:
-- |
-- | 1. Searches the text for the ngrams
-- | 2. Renders each the resulting runs according to the Maybe TermList they appear in
-- |
-- | Notes:
-- |
-- | 1. We must only re-search the text when the ngrams change for performance
-- | 2. We will need a more ambitious search algorithm for skipgrams.
module Gargantext.Components.Annotated.AnnotatedField where
import Prelude hiding (div)
import Data.Unit (Unit, unit)
import Data.Array (fromFoldable)
import Data.Maybe (Maybe(..), isJust)
import Data.Lens (Lens', Prism', over, view, lens)
import Data.List as List
import Data.List (List(..), mapWithIndex, toUnfoldable, sortBy)
import Data.Ordering (Ordering(..))
import Data.Tuple (Tuple(..))
import Effect (Effect)
import React (Children, ReactElement, ReactClass, createElement)
import React.DOM (a, div, p, span, nav, text)
import React.DOM.Props (className, onContextMenu)
import Thermite ( PerformAction, Render, Spec
, defaultPerformAction, createClass
, _render, modifyState, focus, focusState
, simpleSpec, withState)
import Gargantext.Types (TermList(..))
import Gargantext.Components.NgramsTable (NgramsTable, termStyle)
import Gargantext.Utils.React (WithChildren)
import Gargantext.Utils.Selection (getSelection, toString)
import React.SyntheticEvent (SyntheticMouseEvent, pageX, pageY)
newtype PageOffset = PageOffset { x :: Number, y :: Number }
type Run = Tuple String (Maybe TermList)
type State = { runs :: List Run, contextMenu :: { visible :: Boolean } }
type Props' = ( ngrams :: NgramsTable, text :: Maybe String )
type Props = { | Props' }
data Action
= OnContextMenu PageOffset String
| AddTerm String TermList
defaultState :: State
defaultState = { runs: Nil, contextMenu: { visible: false } } -- contextMenu: ContextMenu.defaultState }
annotatedField :: Props -> ReactElement
annotatedField p = createElement annotatedFieldClass p []
annotatedFieldClass :: ReactClass (WithChildren Props')
annotatedFieldClass = createClass "AnnotatedField" spec compile
where
spec :: Spec State Props Action
spec = simpleSpec performAction render
-- performAction (ShowContextMenu i) = showContextMenu i
-- performAction (AddTerm t l) = addTerm t l
performAction :: PerformAction State Props Action
performAction = defaultPerformAction
render :: Render State Props Action
render d _p s _c = [ p [className "annotated-field"] $ children d s.runs ]
children d = fromFoldable <<< map (renderRun $ contextMenuHandler d)
renderRun menu (Tuple txt lst)
| Just list <- lst = span [termStyle list, onContextMenu menu] [text txt]
| otherwise = span [] [text txt]
-- showContextMenu :: PerformAction State Props String
-- showContextMenu p s = pure unit
-- addTerm :: String -> PerformAction State Props TermList
-- addTerm t l p s = pure unit
compile :: Props -> State
compile {text, ngrams} = { runs: runs text, contextMenu: { visible: false } }
where runs (Just txt) = hilite ngrams txt
runs _ = Nil
-- highlightNgrams :: NgramsTable -> String -> Array (Tuple String (Maybe TermList))
-- TODO HOOK IN string search
hilite :: NgramsTable -> String -> List Run
hilite _ _ = List.fromFoldable
[ Tuple "Hello" (Just CandidateTerm)
, Tuple " " Nothing
, Tuple "World" (Just CandidateTerm) ]
-- hilite = map tupleRun <<< highlightNgrams
contextMenuHandler :: (Action -> Effect Unit) -> SyntheticMouseEvent -> Effect Unit
contextMenuHandler d e =
do sel <- getSelection
case toString <$> sel of
Just s -> submit s
Nothing -> pure unit
where submit s = offset >>= \o -> d $ OnContextMenu o s
offset =
do x <- pageX e
y <- pageY e
pure $ PageOffset { x, y }
_runs = lens (\a -> a.runs) (\a r -> a { runs = r })
_contextMenu = lens (\a -> a.contextMenu) (\a m -> a { contextMenu = m })
src/Gargantext/Components/ContextMenu/ContextMenu.purs
0 → 100644
View file @
372acbd0
-- | The ContextMenu component renders a generic context menu
module Gargantext.Component.ContextMenu.ContextMenu where
-- (MenuProps, Action(..), separator) where
import Prelude hiding (div)
import Effect (Effect)
import Data.String (joinWith)
import React
( class ReactComponentSpec
, Context, ContextProvider, ContextConsumer
, ReactClass, ReactElement, ReactClassConstructor, Children
, component, createElement )
import React.DOM (a, div, li, ul')
import React.DOM as DOM -- for Props
import React.DOM.Props (className, onContextMenu, onMouseOut, onBlur)
import Thermite
( Render, PerformAction
, simpleSpec, modifyState_
, createReactSpec, defaultRender
, _render )
import Gargantext.Utils.React (WithChildren, wrap)
-- type State' = { open :: Boolean }
-- newtype State = State State'
-- defaultState :: State
-- defaultState = State { open: false }
-- type MenuProps = { classes :: String, items :: Array (Effect Unit -> ReactElement) }
-- type ItemProps p = { hideMenu :: Context (Effect Unit) | p }
-- data Action = Show | Hide
-- contextMenu :: MenuProps -> ReactElement
-- contextMenu props = createElement contextMenuClass props []
-- -- TODO: register callbacks
-- componentDidMount :: Effect Unit
-- componentDidMount = pure unit
-- -- TODO: unregister callbacks
-- componentWillUnmount :: Effect Unit
-- componentWillUnmount = pure unit
-- --
-- childRender :: forall s p a. Spec s p a -> Spec s p a
-- childRender = over _render (\c -> wrapItem <<< c)
-- -- | Wraps an item in an li tag with the item classname
-- wrapItem :: ReactElement -> ReactElement
-- wrapItem = wrap $ li [ className itemClass ]
-- -- TODO: Aria and accessibility
-- renderMenu :: Render State MenuProps Action
-- renderMenu d m s c = pure $ wrap outer $ ul' inner
-- where outer = div [className (classes s.open m.classes)]
-- inner = map (\i -> renderMenuItem d i ) c
-- visibilityClass :: Boolean -> String
-- visibilityClass true = contextMenuShown
-- visibilityClass false = contextMenuHidden
-- classes :: Boolean -> String -> String
-- classes visible user = joinWith " " [menuClass, visibilityClass visible, user]
-- -- Class
-- contextMenuClass :: ReactClass (WithChildren State')
-- contextMenuClass = component "ContextMenu" createContextMenuClass
-- createContextMenuClass ::
-- forall given snapshot spec.
-- ReactComponentSpec MenuProps State snapshot given spec
-- => ReactClassConstructor MenuProps State given
-- -> ReactClass MenuProps
-- createContextMenuClass this = pure
-- { state: defaultState
-- , render: renderMenu
-- , componentDidMount: componentDidMount
-- , componentWillUnmount: componentWillUnmount
-- }
-- type Label = String
-- type ClassName = String
-- -- Items
-- simpleItem :: Label -> ClassName -> Effect Unit -> ContextConsumer (Effect Unit) -> ReactElement
-- simpleItem label cls cb hide = a [ onClick (hide *> cb), className cls ] [ text label ]
-- separator :: Effect Unit -> ReactElement
-- separator _ = li [ className "menu-item-separator" ] []
-- -- CSS Classes
-- menuClass :: String
-- menuClass = "context-menu"
-- menuShownClass :: String
-- menuShownClass = "context-menu-shown"
-- menuHiddenClass :: String
-- menuHiddenClass = "context-menu-hidden"
-- itemClass :: String
-- itemClass = "context-menu-item"
-- separatorClass :: String
-- separatorClass = "context-menu-item"
src/Gargantext/Components/ContextMenu/SimpleItem.purs
0 → 100644
View file @
372acbd0
-- | The SimpleItem is a simple context menu item consisting of a link
-- | It handles automatically closing the context menu for you
module Gargantext.Component.ContextMenu.SimpleItem where
-- (MenuProps, Action(..), separator) where
import Prelude hiding (div)
import Effect (Effect)
import Data.String (joinWith)
import React
( class ReactComponentSpec
, ReactClass, ReactElement, ReactClassConstructor, Children
, component, createElement )
import React.DOM (a, div, li, ul')
import React.DOM as DOM -- for Props
import React.DOM.Props (className, onContextMenu, onMouseOut, onBlur)
import Thermite
( Render, PerformAction
, simpleSpec, modifyState_
, createReactSpec, defaultRender
, _render )
import Gargantext.Utils.React (WithChildren, wrap)
-- separator :: ReactElement
-- separator = div [ className "context-menu-separator" ] []
-- type State' = { open :: Boolean }
-- newtype State = State State'
-- defaultState :: State
-- defaultState = State { open: false }
-- type MenuProps = { classes :: String }
-- type ItemProps p = { hideMenu :: Effect () | p }
-- data Action = Show | Hide
-- menuClass :: String
-- menuClass = "context-menu"
-- menuShownClass :: String
-- menuShownClass = "context-menu-shown"
-- menuHiddenClass :: String
-- menuHiddenClass = "context-menu-hidden"
-- itemClass :: String
-- itemClass = "context-menu-item"
-- contextMenu :: MenuProps -> Array ReactElement -> ReactElement
-- contextMenu = createElement contextMenuClass
-- -- TODO: register callbacks
-- componentDidMount :: Effect Unit
-- componentDidMount = pure unit
-- -- TODO: unregister callbacks
-- componentWillUnmount :: Effect Unit
-- componentWillUnmount = pure unit
-- --
-- childRender :: forall s p a. Spec s p a -> Spec s p a
-- childRender = over _render (\c -> wrapItem <<< c)
-- -- | Wraps an item in an li tag with the item classname
-- wrapItem :: ReactElement -> ReactElement
-- wrapItem = wrap $ li [ className itemClass ]
-- renderMenuItem :: Render State MenuItem Action MenuItem
-- renderMenuItem _ Separator _ _ = li [ className "menu-item-separator" ]
-- renderMenuItem d (MenuItem i) _ _ = wrap outer inner
-- where outer = li [ className "context-menu-item" ]
-- inner = a [ onClick callback, style i.style ] [text i.label]
-- callback _ = d Hide *> i.callback
-- -- TODO: Aria and accessibility
-- renderMenu :: Render State MenuProps Action
-- renderMenu d m s c = pure $ wrap outer $ ul' inner
-- where outer = div [className (classes s.open m.classes)]
-- inner = map (\i -> renderMenuItem d i ) c
-- visibilityClass :: Boolean -> String
-- visibilityClass true = contextMenuShown
-- visibilityClass false = contextMenuHidden
-- classes :: Boolean -> String -> String
-- classes visible user = joinWith " " [menuClass, visibilityClass visible, user]
-- -- Class
-- contextMenuClass :: ReactClass (WithChildren State')
-- contextMenuClass = component "ContextMenu" createContextMenuClass
-- createContextMenuClass ::
-- forall given snapshot spec.
-- ReactComponentSpec MenuProps State snapshot given spec
-- => ReactClassConstructor MenuProps State given
-- -> ReactClass MenuProps
-- createContextMenuClass this = pure
-- { state: defaultState
-- , render: renderMenu
-- , componentDidMount: componentDidMount
-- , componentWillUnmount: componentWillUnmount
-- }
-- type Label = String
-- type ClassName = String
-- -- Items
-- simpleItem :: Label -> ClassName -> Effect Unit -> Effect Unit -> ReactElement
-- simpleItem label cls cb hide = a [ onClick (hide *> cb), className cls ] [ text label ]
-- separator :: ReactElement
-- separator = li [ className "menu-item-separator" ] []
src/Gargantext/Components/NgramsTable.purs
View file @
372acbd0
...
...
@@ -18,6 +18,7 @@ module Gargantext.Components.NgramsTable
, MainNgramsTableProps
, mainNgramsTableSpec
, highlightNgrams
, termStyle
)
where
...
...
src/Gargantext/Pages/Corpus/Document.purs
View file @
372acbd0
...
...
@@ -5,6 +5,7 @@ import Data.Argonaut (class DecodeJson, class EncodeJson, decodeJson, jsonEmptyO
import Data.Generic.Rep (class Generic)
import Data.Lens (Lens', lens, (?~))
import Data.Generic.Rep.Show (genericShow)
import Data.Map as M
import Data.Maybe (Maybe(..), maybe)
import Data.Either (Either(..))
import Effect.Aff (Aff)
...
...
@@ -19,17 +20,22 @@ import Gargantext.Prelude
import Gargantext.Config (toUrl, NodeType(..), End(..))
import Gargantext.Config.REST (get)
import Gargantext.Components.Node (NodePoly(..))
import Gargantext.Components.NgramsTable (NgramsTable(..))
import Gargantext.Components.Annotated.AnnotatedField as AnnotatedField
type State =
{ document :: Maybe (NodePoly Document)
, annotatedDocument :: AnnotatedDocument
, ngramsTable :: NgramsTable
, inputValue :: String
}
initialState :: {} -> State
initialState {} =
{ document : Nothing
, inputValue : ""
{ document: Nothing
, annotatedDocument: defaultAnnotatedDocument
, ngramsTable: NgramsTable M.empty
, inputValue: ""
}
data Action
...
...
@@ -37,7 +43,6 @@ data Action
| ChangeString String
| SetInput String
newtype Status = Status { failed :: Int
, succeeded :: Int
, remaining :: Int
...
...
@@ -95,27 +100,35 @@ defaultDocumentV3 =
, title : Nothing
}
data Document =
Document { abstract :: Maybe String
, authors :: Maybe String
, bdd :: Maybe String
, doi :: Maybe String
, language_iso2 :: Maybe String
-- , page :: Maybe Int
, publication_date :: Maybe String
--, publication_second :: Maybe Int
--, publication_minute :: Maybe Int
--, publication_hour :: Maybe Int
, publication_day :: Maybe Int
, publication_month :: Maybe Int
, publication_year :: Maybe Int
, source :: Maybe String
, institutes :: Maybe String
, title :: Maybe String
, uniqId :: Maybe String
--, url :: Maybe String
--, text :: Maybe String
}
data Document
= Document
{ abstract :: Maybe String
, authors :: Maybe String
, bdd :: Maybe String
, doi :: Maybe String
, language_iso2 :: Maybe String
-- , page :: Maybe Int
, publication_date :: Maybe String
--, publication_second :: Maybe Int
--, publication_minute :: Maybe Int
--, publication_hour :: Maybe Int
, publication_day :: Maybe Int
, publication_month :: Maybe Int
, publication_year :: Maybe Int
, source :: Maybe String
, institutes :: Maybe String
, title :: Maybe String
, uniqId :: Maybe String
--, url :: Maybe String
--, text :: Maybe String
}
data AnnotatedDocument
= AnnotatedDocument
{ abstract :: AnnotatedField.State }
defaultAnnotatedDocument :: AnnotatedDocument
defaultAnnotatedDocument = AnnotatedDocument { abstract: AnnotatedField.defaultState }
defaultNodeDocument :: NodePoly Document
defaultNodeDocument =
...
...
@@ -286,86 +299,7 @@ docview = simpleSpec performAction render
[
div [className "row"]
[
div [className "col-md-4", style {border : "1px solid black", padding : "34px"}]
[
div [className "row"]
[
div [ className "col-md-12 input-group mb-3"]
[ select [ className "form-control custom-select"
, onChange (\e -> dispatch (ChangeString $ (unsafeCoerce e).target.value))
] $ map optps aryPS
]
]
, div [className "row", style { marginTop : "35px"}]
[
nav [ ]
[ div [ className "nav nav-tabs", _id "nav-tab", role "tablist"]
[ a [ className "nav-item nav-link active"
, _id "nav-home-tab"
, _data {toggle : "tab"},href "#nav-home"
, role "tab"
, aria {controls : "nav-home"}
, aria {selected:true}
] [ text "STOPLIST"]
, a [ className "nav-item nav-link"
, _id "nav-profile-tab"
, _data {toggle : "tab"}
, href "#nav-profile"
, role "tab"
, aria {controls : "nav-profile"}
, aria {selected:true}
] [ text "MAINLIST"]
, a [ className "nav-item nav-link"
, _id "nav-contact-tab"
, _data {toggle : "tab"}
, href "#nav-contact"
, role "tab"
, aria {controls : "nav-contact"}
, aria {selected:true}
] [ text "MAPLIST"]
]
]
, div [className "tab-content" , _id "nav-tabContent"]
[
div [ className "tab-pane fade show active"
, role "tabpanel"
, aria {labelledby : "nav-home-tab"}
, _id "nav-home"
]
[
h6 [] [text "Add a free term to STOPLIST"]
, div [className "form-group"]
[ input [ className "form-control"
, _id "id_password"
, name "password"
, placeholder "Any text"
, _type "value"
, value state.inputValue,onInput \e -> dispatch (SetInput (unsafeEventValue e))
]
, div [className "clearfix"] []
]
, button [ className "btn btn-primary"
, _type "button"
] [text "Create and Add"]
]
, div [ className "tab-pane fade show"
, role "tabpanel"
, aria {labelledby : "nav-profile-tab"}
, _id "nav-profile"
]
[ ]
, div [ className "tab-pane fade show"
, role "tabpanel"
, aria {labelledby : "nav-contact-tab"}
, _id "nav-contact"
]
[ ]
]
]
]
, div [className "col-md-8"]
div [className "col-md-8"]
[ h4 [] [text' document.title]
, ul [className "list-group"]
[ li' [ span [] [text' document.source]
...
...
@@ -382,8 +316,7 @@ docview = simpleSpec performAction render
]
]
, badge "abstract"
, p [] [text' document.abstract]
, abstract
, div [className "jumbotron"]
[ p [] [text "Empty Full Text"]
]
...
...
@@ -392,6 +325,8 @@ docview = simpleSpec performAction render
]
]
where
abs = findInDocument (\(Document d) -> d.abstract) state
abstract = AnnotatedField.annotatedField { ngrams: state.ngramsTable, text: abs }
li' = li [className "list-group-item justify-content-between"]
text' x = text $ maybe "Nothing" identity x
badge s = span [className "badge badge-default badge-pill"] [text s]
...
...
@@ -399,6 +334,11 @@ docview = simpleSpec performAction render
NodePoly {hyperdata : Document document} =
maybe defaultNodeDocument identity state.document
findInDocument :: (Document -> Maybe String) -> State -> Maybe String
findInDocument f state =
do (NodePoly d) <- state.document
f d.hyperdata
aryPS :: Array String
aryPS = ["Map", "Main", "Stop"]
...
...
src/Gargantext/Text/BreakWords.js
0 → 100644
View file @
372acbd0
exports
.
_wordRegex
=
/
[
a-z
]
+/gi
;
exports
.
_cloneRegex
=
function
(
r
)
{
return
new
RegExp
(
r
.
source
,
r
.
flags
);
};
exports
.
_getRegexLastIndex
=
function
(
r
)
{
return
r
.
lastIndex
;
};
exports
.
_execRegex
=
function
(
r
,
s
)
{
return
r
.
exec
(
s
);
};
src/Gargantext/Text/BreakWords.purs
0 → 100644
View file @
372acbd0
-- | Break a string into words and spaces
-- | It uses a simple algorithm of searching for word characters incrementally
-- | Punctuation is considered whitespace, so it's best used in a sentence or
-- | for highlighting purposes
module Gargantext.Text.BreakWords (BrokenWord(..), breakWords) where
import Prelude
import Data.Traversable (traverse_)
import Effect (Effect)
import Data.Maybe (Maybe(..))
import Data.Unit (Unit, unit)
import Effect.Uncurried (EffectFn2, runEffectFn2)
import Data.Function.Uncurried (Fn1, runFn1)
import Data.String.CodeUnits (length, slice) -- TODO: double check i'm the right choice
import Data.Nullable (Nullable, toMaybe)
import Data.String.Regex (Regex)
import Gargantext.Utils.Regex
import Gargantext.Utils.Array (push)
data BrokenWord = Word String | Space String
breakWords :: String -> Effect (Array BrokenWord)
breakWords s = loop $ break s
where loop b = breakNext b >>= (h b)
h :: Breaking -> Boolean -> Effect (Array BrokenWord)
h b cont
| cont = loop b
| otherwise = pure b.results
-- Implementation
-- Returns whether to continue
breakNext :: Breaking -> Effect Boolean
breakNext b = checkStatic b $ lastIndex b
where checkStatic b origin
| origin == length b.source = pure false
| otherwise = search b >>= next' origin
next' origin Nothing = finish b origin
next' origin (Just w) = next b origin w
next :: Breaking -> Int -> String -> Effect Boolean
next b origin word =
do traverse_ (pushSpace b) $ preceding b origin word
pushWord b word
pure true
preceding :: Breaking -> Int -> String -> Maybe String
preceding b origin word = p $ (lastIndex b) - (length word)
where p o
| o == origin = Nothing
| otherwise = slice origin o b.source
finish :: Breaking -> Int -> Effect Boolean
finish b origin =
do let last = slice origin (-1) b.source
traverse_ (pushSpace b) last
pure false
type Breaking = { source :: String, wordRegex :: Regex, results :: Array BrokenWord }
-- almost `pure`
break :: String -> Breaking
break s = { source, wordRegex, results }
where source = s
wordRegex = cloneRegex _wordRegex
results = []
search :: Breaking -> Effect (Maybe String)
search b = execRegex b.wordRegex b.source
lastIndex :: Breaking -> Int
lastIndex b = getRegexLastIndex b.wordRegex
pushResult :: Breaking -> BrokenWord -> Effect Unit
pushResult b = push b.results
pushSpace :: Breaking -> String -> Effect Unit
pushSpace b = pushResult b <<< Space
pushWord :: Breaking -> String -> Effect Unit
pushWord b = pushResult b <<< Word
foreign import _wordRegex :: Regex
src/Gargantext/Types.purs
View file @
372acbd0
...
...
@@ -9,6 +9,8 @@ import Prim.Row (class Union)
data TermSize = MonoTerm | MultiTerm
data Term = Term String TermList
derive instance eqTermSize :: Eq TermSize
instance showTermSize :: Show TermSize where
...
...
@@ -58,6 +60,12 @@ instance showTermList :: Show TermList where
show StopTerm = "StopTerm"
show CandidateTerm = "CandidateTerm"
-- TODO: Can we replace the show instance above with this?
termListName :: TermList -> String
termListName GraphTerm = "Graph List"
termListName StopTerm = "Stop List"
termListName CandidateTerm = "Candidate List"
readTermList :: String -> Maybe TermList
readTermList "GraphTerm" = Just GraphTerm
readTermList "StopTerm" = Just StopTerm
...
...
src/Gargantext/Utils.purs
View file @
372acbd0
module Gargantext.Utils where
import Prelude
import Data.Ordering (Ordering(..))
import Data.Newtype (class Newtype, unwrap, wrap)
import Data.Lens (Lens', lens)
setterv :: forall nt record field. Newtype nt record => (record -> field -> record) -> field -> nt -> nt
setterv fn v t = (setter (flip fn v) t)
...
...
@@ -12,3 +13,13 @@ setter fn = wrap <<< fn <<< unwrap
getter :: forall record field nt. Newtype nt record => (record -> field) -> nt -> field
getter fn = fn <<< unwrap
-- Default sort order is ascending, we may want descending
invertOrdering :: Ordering -> Ordering
invertOrdering LT = GT
invertOrdering GT = LT
invertOrdering EQ = EQ
-- A lens that always returns unit
_unit :: forall s. Lens' s Unit
_unit = lens (\_ -> unit) (\s _ -> s)
src/Gargantext/Utils/Array.js
0 → 100644
View file @
372acbd0
function
_push
(
a
,
i
)
{
a
.
push
(
i
);
}
module
.
exports
=
{
_push
:
_push
};
src/Gargantext/Utils/Array.purs
0 → 100644
View file @
372acbd0
module Gargantext.Utils.Array (push) where
import Effect (Effect)
import Data.Unit (Unit)
import Effect.Uncurried (EffectFn2, runEffectFn2)
foreign import _push :: forall a. EffectFn2 (Array a) a Unit
push :: forall a. Array a -> a -> Effect Unit
push = runEffectFn2 _push
src/Gargantext/Utils/React.purs
0 → 100644
View file @
372acbd0
module Gargantext.Utils.React where
import Prelude
import Data.Array ((!!))
import Data.FoldableWithIndex (foldMapWithIndex)
import Data.Maybe (fromMaybe)
import React (ReactElement, Children)
-- TODO: Upgrade thermite and reapply our changes or upstream them and get rid of this
type WithChildren props = { children :: Children | props }
wrap :: (Array ReactElement -> ReactElement) -> ReactElement -> ReactElement
wrap f e = f [e]
src/Gargantext/Utils/Regex.js
0 → 100644
View file @
372acbd0
function
_cloneRegex
(
r
)
{
return
new
RegExp
(
r
.
source
,
r
.
flags
);
}
function
_getRegexLastIndex
(
r
)
{
return
r
.
lastIndex
;
}
function
_execRegex
(
r
,
s
)
{
return
r
.
exec
(
s
);
}
module
.
exports
=
{
_cloneRegex
:
_cloneRegex
,
_getRegexLastIndex
:
_getRegexLastIndex
,
_execRegex
:
_execRegex
};
src/Gargantext/Utils/Regex.purs
0 → 100644
View file @
372acbd0
-- | Utilities for working with regexes in a naughty mutable manner
module Gargantext.Utils.Regex where
import Effect (Effect)
import Prelude ((<$>))
import Data.Maybe (Maybe(..))
import Effect.Uncurried (EffectFn2, runEffectFn2)
import Data.Function.Uncurried (Fn1, runFn1)
import Data.Nullable (Nullable, toMaybe)
import Data.String.Regex (Regex)
foreign import _cloneRegex :: Fn1 Regex Regex
foreign import _getRegexLastIndex :: Fn1 Regex Int
foreign import _execRegex :: EffectFn2 Regex String (Nullable String)
cloneRegex :: Regex -> Regex
cloneRegex = runFn1 _cloneRegex
getRegexLastIndex :: Regex -> Int
getRegexLastIndex = runFn1 _getRegexLastIndex
execRegex :: Regex -> String -> Effect (Maybe String)
execRegex r s = toMaybe <$> runEffectFn2 _execRegex r s
src/Gargantext/Utils/Selection.js
0 → 100644
View file @
372acbd0
exports
.
_getSelection
=
function
()
{
return
window
.
getSelection
()
||
null
;
};
exports
.
_toString
=
function
(
thing
)
{
return
thing
.
toString
();
};
src/Gargantext/Utils/Selection.purs
0 → 100644
View file @
372acbd0
module Gargantext.Utils.Selection
( class ToString, Selection, toString, getSelection ) where
import Prelude ((<$>))
import Data.Maybe (Maybe)
import Data.Nullable (Nullable, toMaybe)
import Effect (Effect)
-- | Represents a text selection
foreign import data Selection :: Type
-- foreign import data Range :: Type -- Probably coming soon
-- toString
class ToString t
instance toStringSelection :: ToString Selection
-- instance toStringRange :: ToString Range
foreign import _toString :: forall t. t -> String
-- | Renders a selection or range as a string
toString :: forall t. ToString t => t -> String
toString = _toString
-- getSelection
foreign import _getSelection :: Effect (Nullable Selection)
-- | Fetches the current text selection, if any
getSelection :: Effect (Maybe Selection)
getSelection = toMaybe <$> _getSelection
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment