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
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
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
Grégoire Locqueville
purescript-gargantext
Commits
b8ed3d4b
Commit
b8ed3d4b
authored
Jan 17, 2020
by
Przemyslaw Kaminski
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[CodeEditor] more improvements, JSON renders with indent now, errors shown
parent
59af3f6f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
117 additions
and
55 deletions
+117
-55
CodeEditor.purs
src/Gargantext/Components/CodeEditor.purs
+100
-50
Corpus.purs
src/Gargantext/Components/Nodes/Corpus.purs
+1
-1
Reactix.js
src/Gargantext/Utils/Reactix.js
+5
-0
Reactix.purs
src/Gargantext/Utils/Reactix.purs
+11
-4
No files found.
src/Gargantext/Components/CodeEditor.purs
View file @
b8ed3d4b
module Gargantext.Components.CodeEditor where
module Gargantext.Components.CodeEditor where
import Data.Argonaut.Parser (jsonParser)
import Data.Either (either, Either(..))
import Data.Either (either, Either(..))
import Data.Maybe (Maybe(..))
import Data.Maybe (Maybe(..))
import Data.Nullable (Nullable, null, toMaybe)
import Data.Nullable (Nullable, null, toMaybe)
import Data.Tuple (fst)
import Data.Tuple (fst
, snd
)
import Data.Tuple.Nested ((/\))
import Data.Tuple.Nested ((/\))
import DOM.Simple.Console (log, log2)
import DOM.Simple.Console (log, log2)
import DOM.Simple.Types (Element)
import DOM.Simple.Types (Element)
...
@@ -22,6 +23,10 @@ import Text.Smolder.Renderer.String (render)
...
@@ -22,6 +23,10 @@ import Text.Smolder.Renderer.String (render)
import Gargantext.Prelude
import Gargantext.Prelude
import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Reactix as R2
type Code = String
type Html = String
type Error = String
data CodeType = JSON | Markdown
data CodeType = JSON | Markdown
derive instance genericCodeType :: Generic CodeType _
derive instance genericCodeType :: Generic CodeType _
instance eqCodeType :: Eq CodeType where
instance eqCodeType :: Eq CodeType where
...
@@ -38,14 +43,21 @@ instance showViewType :: Show ViewType where
...
@@ -38,14 +43,21 @@ instance showViewType :: Show ViewType where
type Props =
type Props =
( code :: String
( code :: String
,
c
odeType :: CodeType
,
defaultC
odeType :: CodeType
, onChange :: String -> Effect Unit
, onChange :: String -> Effect Unit
)
)
compile :: CodeType -> String -> String
compile :: CodeType -> Code -> Either Error Html
compile JSON code = code
compile JSON code = result
compile Markdown code = compileMd code
where
parsedE = jsonParser code
result = case parsedE of
Left err -> Left err
Right parsed -> Right $ "<pre>" <> (R2.stringify parsed 2) <> "</pre>"
compile Markdown code = Right $ compileMd code
-- TODO Replace with markdown-it?
-- https://pursuit.purescript.org/packages/purescript-markdown-it
compileMd' :: forall e. MD.ToMarkupOptions e -> String -> String
compileMd' :: forall e. MD.ToMarkupOptions e -> String -> String
compileMd' options input =
compileMd' options input =
either identity (MD.toMarkup' options >>> render)
either identity (MD.toMarkup' options >>> render)
...
@@ -60,22 +72,21 @@ codeEditor p = R.createElement codeEditorCpt p []
...
@@ -60,22 +72,21 @@ codeEditor p = R.createElement codeEditorCpt p []
codeEditorCpt :: R.Component Props
codeEditorCpt :: R.Component Props
codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
where
where
cpt {code,
c
odeType, onChange} _ = do
cpt {code,
defaultC
odeType, onChange} _ = do
htmlRef <- R.useRef null
htmlRef <- R.useRef null
codeRef <- R.useRef null
codeRef <- R.useRef null
editorCodeRef <- R.useRef code
editorCodeRef <- R.useRef code
codeTypeS <- R.useState' codeType
codeType <- R.useState' defaultCodeType
error <- R.useState' Nothing
viewType <- R.useState' Both
viewType <- R.useState' Both
-- Initial rendering of elements with given data
-- Note: delay is necessary here, otherwise initially the HTML won't get
-- Note: delay is necessary here, otherwise initially the HTML won't get
-- rendered (mDiv is still null)
-- rendered (mDiv is still null)
R.useEffect $ delay unit $ \_ -> do
R.useEffectOnce $ delay unit $ \_ -> do
let mHtmlEl = toMaybe $ R.readRef htmlRef
_ <- renderHtml (fst codeType) code htmlRef error
case mHtmlEl of
pure $ pure unit
Nothing -> pure $ pure unit
Just htmlEl -> do
_ <- pure $ (htmlEl .= "innerHTML") $ compile codeType code
pure $ pure unit
R.useEffectOnce $ delay unit $ \_ -> do
R.useEffectOnce $ delay unit $ \_ -> do
let mCodeEl = toMaybe $ R.readRef codeRef
let mCodeEl = toMaybe $ R.readRef codeRef
...
@@ -87,20 +98,19 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
...
@@ -87,20 +98,19 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
pure $ H.div { className: "code-editor" } [
pure $ H.div { className: "code-editor" } [
H.div { className: "row toolbar" } [
H.div { className: "row toolbar" } [
codeTypeSelector {codeType: codeTypeS}
codeTypeSelector {codeType, onChange: onChangeCodeType editorCodeRef htmlRef error}
, H.div { className: "btn-group" } [
, viewTypeSelector {state: viewType}
viewTypeButton {viewType: Code, state: viewType}
, viewTypeButton {viewType: Both, state: viewType}
, viewTypeButton {viewType: Preview, state: viewType}
]
]
]
, H.div { className: "row error" } [
errorComponent {error}
]
, H.div { className: "row editor" } [
, H.div { className: "row editor" } [
H.div { className: "code " <> (codeHidden $ fst viewType) } [
H.div { className: "code " <> (codeHidden $ fst viewType) } [
H.code { className: ""
H.code { className: ""
, contentEditable: "true"
, contentEditable: "true"
, ref: codeRef
, ref: codeRef
, rows: 30
, rows: 30
, on: { input: onEditChange
codeType codeRef htmlRef editorCodeRef
}
, on: { input: onEditChange
(fst codeType) codeRef htmlRef editorCodeRef error
}
} []
} []
]
]
, H.div { ref: htmlRef, className: "html " <> (previewHidden $ fst viewType) } []
, H.div { ref: htmlRef, className: "html " <> (previewHidden $ fst viewType) } []
...
@@ -117,8 +127,14 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
...
@@ -117,8 +127,14 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
previewHidden Both = ""
previewHidden Both = ""
previewHidden _ = "hidden"
previewHidden _ = "hidden"
onEditChange :: forall e. CodeType -> R.Ref (Nullable Element) -> R.Ref (Nullable Element) -> R.Ref String -> e -> Effect Unit
-- Handle rerendering of preview when viewType changed
onEditChange codeType codeRef htmlRef editorCodeRef e = do
onChangeCodeType :: R.Ref String -> R.Ref (Nullable Element) -> R.State (Maybe Error) -> CodeType -> Effect Unit
onChangeCodeType editorCodeRef htmlRef error codeType = do
_ <- renderHtml codeType (R.readRef editorCodeRef) htmlRef error
pure unit
onEditChange :: forall e. CodeType -> R.Ref (Nullable Element) -> R.Ref (Nullable Element) -> R.Ref String -> R.State (Maybe Error) -> e -> Effect Unit
onEditChange codeType codeRef htmlRef editorCodeRef error e = do
log2 "[onChange] e" e
log2 "[onChange] e" e
let mCode = toMaybe $ R.readRef codeRef
let mCode = toMaybe $ R.readRef codeRef
case mCode of
case mCode of
...
@@ -126,18 +142,42 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
...
@@ -126,18 +142,42 @@ codeEditorCpt = R.hooksComponent "G.C.CodeEditor" cpt
Just code -> do
Just code -> do
R.setRef editorCodeRef $ R2.innerText code
R.setRef editorCodeRef $ R2.innerText code
pure unit
pure unit
let mHtml = toMaybe $ R.readRef htmlRef
renderHtml codeType (R.readRef editorCodeRef) htmlRef error
case mHtml of
renderHtml :: CodeType -> Code -> R.Ref (Nullable Element) -> R.State (Maybe Error) -> Effect Unit
renderHtml codeType code htmlRef (_ /\ setError) =
case (toMaybe $ R.readRef htmlRef) of
Nothing -> pure unit
Nothing -> pure unit
Just html -> do
Just htmlEl -> do
_ <- pure $ (html .= "innerHTML") $ compile codeType $ R.readRef editorCodeRef
case compile codeType code of
pure unit
Left err -> do
pure unit
setError $ const $ Just err
Right compiled -> do
setError $ const Nothing
_ <- pure $ (htmlEl .= "innerHTML") compiled
pure unit
type ErrorComponentProps =
(
error :: R.State (Maybe Error)
)
errorComponent :: Record ErrorComponentProps -> R.Element
errorComponent p = R.createElement errorComponentCpt p []
errorComponentCpt :: R.Component ErrorComponentProps
errorComponentCpt = R.hooksComponent "G.C.ErrorComponent" cpt
where
cpt {error: (Nothing /\ _)} _ = pure $ H.div {} []
cpt {error: ((Just error) /\ _)} _ = do
pure $ H.div { className: "text-danger" } [ H.text error ]
type CodeTypeSelectorProps =
type CodeTypeSelectorProps =
(
(
codeType :: R.State CodeType
codeType :: R.State CodeType
, onChange :: CodeType -> Effect Unit
)
)
codeTypeSelector :: Record CodeTypeSelectorProps -> R.Element
codeTypeSelector :: Record CodeTypeSelectorProps -> R.Element
...
@@ -146,49 +186,59 @@ codeTypeSelector p = R.createElement codeTypeSelectorCpt p []
...
@@ -146,49 +186,59 @@ codeTypeSelector p = R.createElement codeTypeSelectorCpt p []
codeTypeSelectorCpt :: R.Component CodeTypeSelectorProps
codeTypeSelectorCpt :: R.Component CodeTypeSelectorProps
codeTypeSelectorCpt = R.hooksComponent "G.C.CodeTypeSelector" cpt
codeTypeSelectorCpt = R.hooksComponent "G.C.CodeTypeSelector" cpt
where
where
cpt {codeType} _ = do
cpt {codeType
, onChange
} _ = do
pure $ R2.select { className: "form-control"
pure $ R2.select { className: "form-control"
, on: { change: onSelectChange codeType }
, on: { change: onSelectChange codeType
onChange
}
, style: { width: "150px" }
, style: { width: "150px" }
, value: show $ fst codeType }
, value: show $ fst codeType }
(option <$> [JSON, Markdown])
(option <$> [JSON, Markdown])
option :: CodeType -> R.Element
option :: CodeType -> R.Element
option value = H.option { value: show value } [ H.text $ show value ]
option value = H.option { value: show value } [ H.text $ show value ]
onSelectChange (_ /\ setCodeType) e = do
onSelectChange :: forall e. R.State CodeType -> (CodeType -> Effect Unit) -> e -> Effect Unit
onSelectChange (_ /\ setCodeType) onChange e = do
let codeType = case value of
let codeType = case value of
"JSON" -> JSON
"JSON" -> JSON
"Markdown" -> Markdown
"Markdown" -> Markdown
_ -> Markdown
_ -> Markdown
setCodeType $ const codeType
setCodeType $ const codeType
onChange codeType
where
where
value = R2.unsafeEventValue e
value = R2.unsafeEventValue e
type ViewTypeProps =
type ViewType
Selector
Props =
(
(
viewType :: ViewType
state :: R.State ViewType
, state :: R.State ViewType
)
)
viewType
Button :: Record ViewType
Props -> R.Element
viewType
Selector :: Record ViewTypeSelector
Props -> R.Element
viewType
Button p = R.createElement viewTypeButton
Cpt p []
viewType
Selector p = R.createElement viewTypeSelector
Cpt p []
viewType
ButtonCpt :: R.Component ViewType
Props
viewType
SelectorCpt :: R.Component ViewTypeSelector
Props
viewType
ButtonCpt = R.hooksComponent "G.C.ViewTypeButton
" cpt
viewType
SelectorCpt = R.hooksComponent "G.C.ViewTypeSelector
" cpt
where
where
cpt {viewType, state: (state /\ setState)} _ =
cpt {state} _ =
pure $ H.label {
pure $ H.div { className: "btn-group" } [
className: "btn btn-default" <> (active viewType state)
viewTypeButton Code state
, on: { click: onClick viewType setState }
, viewTypeButton Both state
} [
, viewTypeButton Preview state
H.i { className: "glyphicon " <> (icon viewType) } []
]
]
active viewType state = if viewType == state then " active" else ""
viewTypeButton viewType (state /\ setState) =
H.label {
className: "btn btn-default" <> active
, on: { click: onClick }
} [
H.i { className: "glyphicon " <> (icon viewType) } []
]
where
active = if viewType == state then " active" else ""
onClick _ = do
setState $ const viewType
icon Preview = "glyphicon-eye-open"
icon Preview = "glyphicon-eye-open"
icon Both = "glyphicon-transfer"
icon Both = "glyphicon-transfer"
icon Code = "glyphicon-pencil"
icon Code = "glyphicon-pencil"
onClick viewType setState _ = setState $ const viewType
src/Gargantext/Components/Nodes/Corpus.purs
View file @
b8ed3d4b
...
@@ -28,7 +28,7 @@ corpusLayoutCpt = R.hooksComponent "G.P.Corpus.corpusLayout" cpt
...
@@ -28,7 +28,7 @@ corpusLayoutCpt = R.hooksComponent "G.P.Corpus.corpusLayout" cpt
cpt {nodeId} _ = do
cpt {nodeId} _ = do
pure $ H.div {}
pure $ H.div {}
[
[
CE.codeEditor {code,
c
odeType: CE.Markdown, onChange}
CE.codeEditor {code,
defaultC
odeType: CE.Markdown, onChange}
--H.iframe { src: gargMd , width: "100%", height: "100%", style: {"border-style": "none"}} []
--H.iframe { src: gargMd , width: "100%", height: "100%", style: {"border-style": "none"}} []
]
]
--gargMd = "https://hackmd.iscpif.fr/g9Aah4iwQtCayIzsKQjA0Q#"
--gargMd = "https://hackmd.iscpif.fr/g9Aah4iwQtCayIzsKQjA0Q#"
...
...
src/Gargantext/Utils/Reactix.js
View file @
b8ed3d4b
...
@@ -11,5 +11,10 @@ function getSelection(_u) {
...
@@ -11,5 +11,10 @@ function getSelection(_u) {
return
window
.
getSelection
();
return
window
.
getSelection
();
}
}
function
stringify
(
j
,
indent
)
{
return
JSON
.
stringify
(
j
,
null
,
indent
);
}
exports
.
_addRootElement
=
addRootElement
;
exports
.
_addRootElement
=
addRootElement
;
exports
.
_getSelection
=
getSelection
;
exports
.
_getSelection
=
getSelection
;
exports
.
_stringify
=
stringify
;
src/Gargantext/Utils/Reactix.purs
View file @
b8ed3d4b
...
@@ -2,16 +2,18 @@ module Gargantext.Utils.Reactix where
...
@@ -2,16 +2,18 @@ module Gargantext.Utils.Reactix where
import Prelude
import Prelude
import Data.Argonaut.Core (Json)
import Data.Function.Uncurried (Fn2, runFn2)
import Data.Maybe (Maybe(..), fromJust)
import Data.Nullable (Nullable, null, toMaybe)
import Data.Tuple (Tuple)
import Data.Tuple.Nested ((/\))
import DOM.Simple as DOM
import DOM.Simple as DOM
import DOM.Simple.Console (log2)
import DOM.Simple.Console (log2)
import DOM.Simple.Document (document)
import DOM.Simple.Document (document)
import DOM.Simple.Element as Element
import DOM.Simple.Element as Element
import DOM.Simple.Event as DE
import DOM.Simple.Event as DE
import DOM.Simple.Types (class IsNode)
import DOM.Simple.Types (class IsNode)
import Data.Maybe (Maybe(..), fromJust)
import Data.Nullable (Nullable, null, toMaybe)
import Data.Tuple (Tuple)
import Data.Tuple.Nested ((/\))
import Effect (Effect)
import Effect (Effect)
import Effect.Aff (Aff, launchAff, launchAff_, killFiber)
import Effect.Aff (Aff, launchAff, launchAff_, killFiber)
import Effect.Class (liftEffect)
import Effect.Class (liftEffect)
...
@@ -242,3 +244,8 @@ getSelection :: Unit -> Effect Selection
...
@@ -242,3 +244,8 @@ getSelection :: Unit -> Effect Selection
getSelection = runEffectFn1 _getSelection
getSelection = runEffectFn1 _getSelection
foreign import _getSelection :: EffectFn1 Unit Selection
foreign import _getSelection :: EffectFn1 Unit Selection
stringify :: Json -> Int -> String
stringify j indent = runFn2 _stringify j indent
foreign import _stringify :: Fn2 Json Int String
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