Commit c27949bd authored by Przemyslaw Kaminski's avatar Przemyslaw Kaminski

[toestand] rewrite CodeEditor to toestand

parent 19595b16
...@@ -19,10 +19,12 @@ import Text.Markdown.SlamDown.Parser (parseMd) ...@@ -19,10 +19,12 @@ import Text.Markdown.SlamDown.Parser (parseMd)
import Text.Markdown.SlamDown.Smolder as MD import Text.Markdown.SlamDown.Smolder as MD
import Text.Markdown.SlamDown.Syntax (SlamDownP) import Text.Markdown.SlamDown.Syntax (SlamDownP)
import Text.Smolder.Renderer.String as Smolder import Text.Smolder.Renderer.String as Smolder
import Toestand as T
import Gargantext.Prelude import Gargantext.Prelude
import Gargantext.Utils.HighlightJS as HLJS import Gargantext.Utils.HighlightJS as HLJS
import Gargantext.Utils.Reactix as R2 import Gargantext.Utils.Reactix as R2
import Gargantext.Utils.Toestand as T2
here :: R2.Here here :: R2.Here
here = R2.here "Gargantext.Components.CodeEditor" here = R2.here "Gargantext.Components.CodeEditor"
...@@ -30,6 +32,7 @@ here = R2.here "Gargantext.Components.CodeEditor" ...@@ -30,6 +32,7 @@ here = R2.here "Gargantext.Components.CodeEditor"
type Code = String type Code = String
type Html = String type Html = String
type Error = String type Error = String
type ElRef = R.Ref (Nullable Element)
data CodeType = Haskell | JSON | Markdown | Python data CodeType = Haskell | JSON | Markdown | Python
...@@ -113,23 +116,26 @@ codeEditorCpt = here.component "codeEditor" cpt ...@@ -113,23 +116,26 @@ codeEditorCpt = here.component "codeEditor" cpt
cpt {code, defaultCodeType, onChange} _ = do cpt {code, defaultCodeType, onChange} _ = do
controls <- initControls code defaultCodeType controls <- initControls code defaultCodeType
R.useEffect2' (fst controls.codeS) (fst controls.codeType) $ do codeS' <- T.useLive T.unequal controls.codeS
let code' = fst controls.codeS codeType' <- T.useLive T.unequal controls.codeType
setCodeOverlay controls code' viewType' <- T.useLive T.unequal controls.viewType
renderHtml code' controls
R.useEffect2' codeS' codeType' $ do
setCodeOverlay controls.codeOverlayElRef codeType' codeS'
renderHtml codeS' codeType' controls.htmlElRef controls.error
pure $ H.div { className: "code-editor" } pure $ H.div { className: "code-editor" }
[ toolbar {controls, onChange} [ toolbar { controls, onChange }
, H.div { className: "row error" } , H.div { className: "row error" }
[ errorComponent {error: controls.error} ] [ errorComponent {error: controls.error} ]
, H.div { className: "row editor" } , H.div { className: "row editor" }
[ H.div { className: "code-area " <> (codeHidden $ fst controls.viewType) } [ H.div { className: "code-area " <> (codeHidden viewType') }
[ H.div { className: "code-container" } [ H.div { className: "code-container" }
[ H.textarea { defaultValue: code [ H.textarea { defaultValue: codeS'
, on: { change: onEditChange controls onChange } , on: { change: onEditChange controls.codeS codeType' onChange }
, placeholder: "Type some code..." , placeholder: "Type some code..."
, ref: controls.codeElRef } [ ] , ref: controls.codeElRef } [ ]
, H.pre { className: (langClass $ fst controls.codeType) , H.pre { className: (langClass codeType')
-- , contentEditable: "true" -- , contentEditable: "true"
, ref: controls.codeOverlayElRef , ref: controls.codeOverlayElRef
, rows: 30 , rows: 30
...@@ -137,8 +143,8 @@ codeEditorCpt = here.component "codeEditor" cpt ...@@ -137,8 +143,8 @@ codeEditorCpt = here.component "codeEditor" cpt
} [] } []
] ]
] ]
, H.div { className: "v-divider " <> (dividerHidden $ fst controls.viewType) } [ H.text " " ] , H.div { className: "v-divider " <> (dividerHidden viewType') } [ H.text " " ]
, H.div { className: "html " <> (langClass $ fst controls.codeType) <> (previewHidden $ fst controls.viewType) , H.div { className: "html " <> (langClass codeType') <> (previewHidden viewType')
, ref: controls.htmlElRef , ref: controls.htmlElRef
} [] } []
] ]
...@@ -164,14 +170,14 @@ codeEditorCpt = here.component "codeEditor" cpt ...@@ -164,14 +170,14 @@ codeEditorCpt = here.component "codeEditor" cpt
previewHidden Both = "" previewHidden Both = ""
previewHidden _ = " d-none" previewHidden _ = " d-none"
onEditChange :: forall e. Record Controls -> (CodeType -> Code -> Effect Unit) -> e -> Effect Unit onEditChange :: forall e. T.Box Code -> CodeType -> OnChangeCodeType -> e -> Effect Unit
onEditChange controls@{codeElRef, codeOverlayElRef, codeType: (codeType /\ _), codeS} onChange e = do onEditChange codeS codeType onChange e = do
let code = R.unsafeEventValue e let code = R.unsafeEventValue e
snd codeS $ const code T.write_ code codeS
onChange codeType code onChange codeType code
setCodeOverlay :: Record Controls -> Code -> Effect Unit setCodeOverlay :: ElRef -> CodeType -> Code -> Effect Unit
setCodeOverlay {codeOverlayElRef, codeType: (codeType /\ _)} code = do setCodeOverlay codeOverlayElRef codeType code = do
let mCodeOverlayEl = toMaybe $ R.readRef codeOverlayElRef let mCodeOverlayEl = toMaybe $ R.readRef codeOverlayElRef
_ <- case mCodeOverlayEl of _ <- case mCodeOverlayEl of
Nothing -> pure unit Nothing -> pure unit
...@@ -181,23 +187,25 @@ setCodeOverlay {codeOverlayElRef, codeType: (codeType /\ _)} code = do ...@@ -181,23 +187,25 @@ setCodeOverlay {codeOverlayElRef, codeType: (codeType /\ _)} code = do
pure unit pure unit
pure unit pure unit
renderHtml :: Code -> Record Controls -> Effect Unit renderHtml :: Code -> CodeType -> ElRef -> T.Box (Maybe Error) -> Effect Unit
renderHtml code {codeType: (codeType /\ _), htmlElRef, error: (_ /\ setError)} = renderHtml code codeType htmlElRef error =
case (toMaybe $ R.readRef htmlElRef) of case (toMaybe $ R.readRef htmlElRef) of
Nothing -> pure unit Nothing -> pure unit
Just htmlEl -> do Just htmlEl -> do
case render codeType code of case render codeType code of
Left err -> do Left err -> do
setError $ const $ Just err T.write_ (Just err) error
Right rendered -> do Right rendered -> do
setError $ const Nothing T.write_ Nothing error
_ <- pure $ (htmlEl .= "innerHTML") rendered _ <- pure $ (htmlEl .= "innerHTML") rendered
previewPostProcess codeType htmlEl previewPostProcess codeType htmlEl
pure unit pure unit
type OnChangeCodeType = CodeType -> Code -> Effect Unit
type ToolbarProps = ( type ToolbarProps = (
controls :: Record Controls controls :: Record Controls
, onChange :: CodeType -> Code -> Effect Unit , onChange :: OnChangeCodeType
) )
toolbar :: Record ToolbarProps -> R.Element toolbar :: Record ToolbarProps -> R.Element
...@@ -206,30 +214,28 @@ toolbar p = R.createElement toolbarCpt p [] ...@@ -206,30 +214,28 @@ toolbar p = R.createElement toolbarCpt p []
toolbarCpt :: R.Component ToolbarProps toolbarCpt :: R.Component ToolbarProps
toolbarCpt = here.component "toolbar" cpt toolbarCpt = here.component "toolbar" cpt
where where
cpt props@{controls: {codeType, error, viewType}} _ = do cpt props@{ controls: { codeS, codeType, error, viewType }
, onChange } _ = do
codeS' <- T.useLive T.unequal codeS
codeType' <- T.useLive T.unequal codeType
pure $ pure $
H.div { className: "row toolbar" } H.div { className: "row toolbar" }
[ H.div { className: "col-2" } [ H.div { className: "col-2" }
[ codeTypeSelector { [ codeTypeSelector {
codeType codeType
, onChange: onChangeCodeType props -- Handle rerendering of preview when viewType changed
, onChange: \ct -> onChange ct codeS'
} }
] ]
, H.div { className: "col-1" } , H.div { className: "col-1" }
[ viewTypeSelector {state: viewType} ] [ viewTypeSelector {state: viewType} [] ]
] ]
-- Handle rerendering of preview when viewType changed
onChangeCodeType :: forall e. Record ToolbarProps -> e -> Effect Unit
onChangeCodeType {controls, onChange} _ = do
onChange (fst controls.codeType) code
where
code = fst controls.codeS
type ErrorComponentProps = type ErrorComponentProps =
( (
error :: R.State (Maybe Error) error :: T.Box (Maybe Error)
) )
errorComponent :: Record ErrorComponentProps -> R.Element errorComponent :: Record ErrorComponentProps -> R.Element
...@@ -238,14 +244,17 @@ errorComponent p = R.createElement errorComponentCpt p [] ...@@ -238,14 +244,17 @@ errorComponent p = R.createElement errorComponentCpt p []
errorComponentCpt :: R.Component ErrorComponentProps errorComponentCpt :: R.Component ErrorComponentProps
errorComponentCpt = here.component "errorComponent" cpt errorComponentCpt = here.component "errorComponent" cpt
where where
cpt {error: (Nothing /\ _)} _ = pure $ H.div {} [] cpt { error } _ = do
cpt {error: ((Just error) /\ _)} _ = do error' <- T.useLive T.unequal error
pure $ H.div { className: "text-danger" } [ H.text error ]
pure $ case error' of
Nothing -> H.div {} []
Just err -> H.div { className: "text-danger" } [ H.text err ]
type CodeTypeSelectorProps = type CodeTypeSelectorProps =
( (
codeType :: R.State CodeType codeType :: T.Box CodeType
, onChange :: CodeType -> Effect Unit , onChange :: CodeType -> Effect Unit
) )
...@@ -255,9 +264,11 @@ codeTypeSelector p = R.createElement codeTypeSelectorCpt p [] ...@@ -255,9 +264,11 @@ codeTypeSelector p = R.createElement codeTypeSelectorCpt p []
codeTypeSelectorCpt :: R.Component CodeTypeSelectorProps codeTypeSelectorCpt :: R.Component CodeTypeSelectorProps
codeTypeSelectorCpt = here.component "codeTypeSelector" cpt codeTypeSelectorCpt = here.component "codeTypeSelector" cpt
where where
cpt {codeType, onChange} _ = do cpt { codeType, onChange } _ = do
codeType' <- T.useLive T.unequal codeType
pure $ R2.select { className: "form-control" pure $ R2.select { className: "form-control"
, defaultValue: show $ fst codeType , defaultValue: show codeType'
, on: { change: onSelectChange codeType onChange } , on: { change: onSelectChange codeType onChange }
, style: { width: "150px" } , style: { width: "150px" }
} }
...@@ -266,51 +277,50 @@ codeTypeSelectorCpt = here.component "codeTypeSelector" cpt ...@@ -266,51 +277,50 @@ codeTypeSelectorCpt = here.component "codeTypeSelector" cpt
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 :: forall e. R.State CodeType -> (CodeType -> Effect Unit) -> e -> Effect Unit onSelectChange :: forall e. T.Box CodeType -> (CodeType -> Effect Unit) -> e -> Effect Unit
onSelectChange (_ /\ setCodeType) onChange e = do onSelectChange codeType onChange e = do
let codeType = case value of let ct = case value of
"Haskell" -> Haskell "Haskell" -> Haskell
"JSON" -> JSON "JSON" -> JSON
"Markdown" -> Markdown "Markdown" -> Markdown
"Python" -> Python "Python" -> Python
_ -> Markdown _ -> Markdown
setCodeType $ const codeType T.write_ ct codeType
onChange codeType onChange ct
where where
value = R.unsafeEventValue e value = R.unsafeEventValue e
type ViewTypeSelectorProps = type ViewTypeSelectorProps =
( (
state :: R.State ViewType state :: T.Box ViewType
) )
viewTypeSelector :: Record ViewTypeSelectorProps -> R.Element viewTypeSelector :: R2.Component ViewTypeSelectorProps
viewTypeSelector p = R.createElement viewTypeSelectorCpt p [] viewTypeSelector = R.createElement viewTypeSelectorCpt
viewTypeSelectorCpt :: R.Component ViewTypeSelectorProps viewTypeSelectorCpt :: R.Component ViewTypeSelectorProps
viewTypeSelectorCpt = here.component "viewTypeSelector" cpt viewTypeSelectorCpt = here.component "viewTypeSelector" cpt
where where
cpt {state} _ = cpt { state } _ = do
state' <- T.useLive T.unequal state
pure $ H.div { className: "btn-group" pure $ H.div { className: "btn-group"
, role: "group" } [ , role: "group" } [
viewTypeButton Code state viewTypeButton Code state' state
, viewTypeButton Both state , viewTypeButton Both state' state
, viewTypeButton Preview state , viewTypeButton Preview state' state
] ]
viewTypeButton viewType (state /\ setState) = viewTypeButton viewType state' state =
H.button { className: "btn btn-primary" <> active H.button { className: "btn btn-primary" <> active
, on: { click: onClick } , on: { click: \_ -> T.write viewType state }
, type: "button" , type: "button"
} [ } [
H.i { className: "fa " <> (icon viewType) } [] H.i { className: "fa " <> (icon viewType) } []
] ]
where where
active = if viewType == state then " active" else "" active = if viewType == state' then " active" else ""
onClick _ = do
setState $ const viewType
icon Preview = "fa-eye" icon Preview = "fa-eye"
icon Both = "fa-columns" icon Both = "fa-columns"
...@@ -319,23 +329,23 @@ viewTypeSelectorCpt = here.component "viewTypeSelector" cpt ...@@ -319,23 +329,23 @@ viewTypeSelectorCpt = here.component "viewTypeSelector" cpt
type Controls = type Controls =
( (
codeElRef :: R.Ref (Nullable Element) codeElRef :: R.Ref (Nullable Element)
, codeS :: R.State Code , codeS :: T.Box Code
, codeType :: R.State CodeType , codeType :: T.Box CodeType
, codeOverlayElRef :: R.Ref (Nullable Element) , codeOverlayElRef :: R.Ref (Nullable Element)
, error :: R.State (Maybe Error) , error :: T.Box (Maybe Error)
, htmlElRef :: R.Ref (Nullable Element) , htmlElRef :: R.Ref (Nullable Element)
, viewType :: R.State ViewType , viewType :: T.Box ViewType
) )
initControls :: Code -> CodeType -> R.Hooks (Record Controls) initControls :: Code -> CodeType -> R.Hooks (Record Controls)
initControls code defaultCodeType = do initControls code defaultCodeType = do
htmlElRef <- R.useRef null htmlElRef <- R.useRef null
codeS <- R.useState' code codeS <- T.useBox code
codeElRef <- R.useRef null codeElRef <- R.useRef null
codeOverlayElRef <- R.useRef null codeOverlayElRef <- R.useRef null
codeType <- R.useState' defaultCodeType codeType <- T.useBox defaultCodeType
error <- R.useState' Nothing error <- T.useBox Nothing
viewType <- R.useState' Preview viewType <- T.useBox Preview
pure $ { pure $ {
codeElRef codeElRef
...@@ -348,7 +358,7 @@ initControls code defaultCodeType = do ...@@ -348,7 +358,7 @@ initControls code defaultCodeType = do
} }
reinitControls :: Record Controls -> Code -> CodeType -> Effect Unit reinitControls :: Record Controls -> Code -> CodeType -> Effect Unit
reinitControls c@{codeType, codeS, error} code defaultCodeType = do reinitControls c@{ codeType, codeS, error } code defaultCodeType = do
snd codeType $ const defaultCodeType T.write_ defaultCodeType codeType
snd codeS $ const code T.write_ code codeS
snd error $ const Nothing T.write_ Nothing error
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