display API/Validation errors in UI
This commit is contained in:
parent
2d3b3c3831
commit
cfe85747b6
|
@ -48,9 +48,9 @@ editBookmark :: Bookmark -> Aff (Either Error (Response String))
|
||||||
editBookmark bm = do
|
editBookmark bm = do
|
||||||
fetchJson POST "api/add" (Just (Bookmark' bm)) AXRes.string
|
fetchJson POST "api/add" (Just (Bookmark' bm)) AXRes.string
|
||||||
|
|
||||||
editNote :: Note -> Aff (Either Error (Response Json))
|
editNote :: Note -> Aff (Either Error (Response String))
|
||||||
editNote bm = do
|
editNote bm = do
|
||||||
fetchJson POST "api/note/add" (Just (Note' bm)) AXRes.json
|
fetchJson POST "api/note/add" (Just (Note' bm)) AXRes.string
|
||||||
|
|
||||||
lookupTitle :: Bookmark -> Aff (Maybe String)
|
lookupTitle :: Bookmark -> Aff (Maybe String)
|
||||||
lookupTitle bm = do
|
lookupTitle bm = do
|
||||||
|
|
|
@ -10,7 +10,7 @@ import Halogen as H
|
||||||
import Halogen.HTML (div, input, text)
|
import Halogen.HTML (div, input, text)
|
||||||
import Halogen.HTML.Elements (label)
|
import Halogen.HTML.Elements (label)
|
||||||
import Halogen.HTML.Events (onChecked)
|
import Halogen.HTML.Events (onChecked)
|
||||||
import Halogen.HTML.Properties (InputType(..), checked, for, id_, name, type_)
|
import Halogen.HTML.Properties (InputType(..), checked, for, id, name, type_)
|
||||||
import Model (AccountSettings)
|
import Model (AccountSettings)
|
||||||
import Util (class_)
|
import Util (class_)
|
||||||
import Web.Event.Event (Event)
|
import Web.Event.Event (Event)
|
||||||
|
@ -52,19 +52,19 @@ usetting u' =
|
||||||
div [ class_ "settings-form" ]
|
div [ class_ "settings-form" ]
|
||||||
[ div [ class_ "fw7 mb2"] [ text "Account Settings" ]
|
[ div [ class_ "fw7 mb2"] [ text "Account Settings" ]
|
||||||
, div [ class_ "flex items-center mb2" ]
|
, div [ class_ "flex items-center mb2" ]
|
||||||
[ input [ type_ InputCheckbox , class_ "pointer mr2" , id_ "archiveDefault", name "archiveDefault"
|
[ input [ type_ InputCheckbox , class_ "pointer mr2" , id "archiveDefault", name "archiveDefault"
|
||||||
, checked (us.archiveDefault) , onChecked (editField EarchiveDefault) ]
|
, checked (us.archiveDefault) , onChecked (editField EarchiveDefault) ]
|
||||||
, label [ for "archiveDefault", class_ "lh-copy" ]
|
, label [ for "archiveDefault", class_ "lh-copy" ]
|
||||||
[ text "Archive Non-Private Bookmarks (archive.li)" ]
|
[ text "Archive Non-Private Bookmarks (archive.li)" ]
|
||||||
]
|
]
|
||||||
, div [ class_ "flex items-center mb2" ]
|
, div [ class_ "flex items-center mb2" ]
|
||||||
[ input [ type_ InputCheckbox , class_ "pointer mr2" , id_ "privateDefault", name "privateDefault"
|
[ input [ type_ InputCheckbox , class_ "pointer mr2" , id "privateDefault", name "privateDefault"
|
||||||
, checked (us.privateDefault) , onChecked (editField EprivateDefault) ]
|
, checked (us.privateDefault) , onChecked (editField EprivateDefault) ]
|
||||||
, label [ for "privateDefault", class_ "lh-copy" ]
|
, label [ for "privateDefault", class_ "lh-copy" ]
|
||||||
[ text "Default new bookmarks to Private" ]
|
[ text "Default new bookmarks to Private" ]
|
||||||
]
|
]
|
||||||
, div [ class_ "flex items-center mb2" ]
|
, div [ class_ "flex items-center mb2" ]
|
||||||
[ input [ type_ InputCheckbox , class_ "pointer mr2" , id_ "privacyLock", name "privacyLock"
|
[ input [ type_ InputCheckbox , class_ "pointer mr2" , id "privacyLock", name "privacyLock"
|
||||||
, checked (us.privacyLock) , onChecked (editField EprivacyLock) ]
|
, checked (us.privacyLock) , onChecked (editField EprivacyLock) ]
|
||||||
, label [ for "privacyLock", class_ "lh-copy" ]
|
, label [ for "privacyLock", class_ "lh-copy" ]
|
||||||
[ text "Privacy Lock (Private Account)" ]
|
[ text "Privacy Lock (Private Account)" ]
|
||||||
|
|
|
@ -7,18 +7,18 @@ import Affjax.StatusCode (StatusCode(..))
|
||||||
import App (destroy, editBookmark, lookupTitle)
|
import App (destroy, editBookmark, lookupTitle)
|
||||||
import Data.Either (Either(..))
|
import Data.Either (Either(..))
|
||||||
import Data.Lens (Lens', lens, use, (%=), (.=))
|
import Data.Lens (Lens', lens, use, (%=), (.=))
|
||||||
import Data.Maybe (Maybe(..), maybe, isJust)
|
import Data.Maybe (Maybe(..), fromMaybe, isJust, maybe)
|
||||||
import Data.Monoid (guard)
|
import Data.Monoid (guard)
|
||||||
import Data.String (Pattern(..), null, stripPrefix)
|
import Data.String (Pattern(..), null, stripPrefix)
|
||||||
import Data.Tuple (fst, snd)
|
import Data.Tuple (fst, snd)
|
||||||
import Effect.Aff (Aff)
|
import Effect.Aff (Aff)
|
||||||
import Effect.Class (liftEffect)
|
import Effect.Class (liftEffect)
|
||||||
import Effect.Console (log)
|
import Effect.Console (log)
|
||||||
import Globals (app', closeWindow, mmoment8601)
|
import Globals (closeWindow, mmoment8601)
|
||||||
import Halogen as H
|
import Halogen as H
|
||||||
import Halogen.HTML (button, div, form, input, label, p, span, table, tbody_, td, td_, text, textarea, tr_)
|
import Halogen.HTML (button, div, form, input, label, p, span, table, tbody_, td, td_, text, textarea, tr_)
|
||||||
import Halogen.HTML.Events (onSubmit, onValueChange, onChecked, onClick)
|
import Halogen.HTML.Events (onSubmit, onValueChange, onChecked, onClick)
|
||||||
import Halogen.HTML.Properties (ButtonType(..), InputType(..), autocomplete, autofocus, checked, disabled, for, id_, name, required, rows, title, type_, value)
|
import Halogen.HTML.Properties (ButtonType(..), InputType(..), autocomplete, autofocus, checked, disabled, for, id, name, required, rows, title, type_, value)
|
||||||
import Model (Bookmark)
|
import Model (Bookmark)
|
||||||
import Util (_curQuerystring, _loc, _doc, _lookupQueryStringValue, attr, class_, ifElseH, whenH)
|
import Util (_curQuerystring, _loc, _doc, _lookupQueryStringValue, attr, class_, ifElseH, whenH)
|
||||||
import Web.Event.Event (Event, preventDefault)
|
import Web.Event.Event (Event, preventDefault)
|
||||||
|
@ -47,6 +47,7 @@ type BState =
|
||||||
, deleteAsk :: Boolean
|
, deleteAsk :: Boolean
|
||||||
, loading :: Boolean
|
, loading :: Boolean
|
||||||
, destroyed :: Boolean
|
, destroyed :: Boolean
|
||||||
|
, apiError :: Maybe String
|
||||||
}
|
}
|
||||||
|
|
||||||
_bm :: Lens' BState Bookmark
|
_bm :: Lens' BState Bookmark
|
||||||
|
@ -55,6 +56,9 @@ _bm = lens _.bm (_ { bm = _ })
|
||||||
_edit_bm :: Lens' BState Bookmark
|
_edit_bm :: Lens' BState Bookmark
|
||||||
_edit_bm = lens _.edit_bm (_ { edit_bm = _ })
|
_edit_bm = lens _.edit_bm (_ { edit_bm = _ })
|
||||||
|
|
||||||
|
_apiError :: Lens' BState (Maybe String)
|
||||||
|
_apiError = lens _.apiError (_ { apiError = _ })
|
||||||
|
|
||||||
addbmark :: forall q i o. Bookmark -> H.Component q i o Aff
|
addbmark :: forall q i o. Bookmark -> H.Component q i o Aff
|
||||||
addbmark b' =
|
addbmark b' =
|
||||||
H.mkComponent
|
H.mkComponent
|
||||||
|
@ -63,7 +67,6 @@ addbmark b' =
|
||||||
, eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
|
, eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
app = app' unit
|
|
||||||
|
|
||||||
mkState b =
|
mkState b =
|
||||||
{ bm: b
|
{ bm: b
|
||||||
|
@ -71,10 +74,11 @@ addbmark b' =
|
||||||
, deleteAsk: false
|
, deleteAsk: false
|
||||||
, destroyed: false
|
, destroyed: false
|
||||||
, loading: false
|
, loading: false
|
||||||
|
, apiError: Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
render :: forall m. BState -> H.ComponentHTML BAction () m
|
render :: forall m. BState -> H.ComponentHTML BAction () m
|
||||||
render s@{ bm, edit_bm } =
|
render s@{ bm, edit_bm, apiError } =
|
||||||
ifElseH (not s.destroyed)
|
ifElseH (not s.destroyed)
|
||||||
display_edit
|
display_edit
|
||||||
display_destroyed
|
display_destroyed
|
||||||
|
@ -86,39 +90,41 @@ addbmark b' =
|
||||||
[ tr_
|
[ tr_
|
||||||
[ td [ class_ "w1" ] [ ]
|
[ td [ class_ "w1" ] [ ]
|
||||||
, td_ [ whenH (bm.bid > 0)
|
, td_ [ whenH (bm.bid > 0)
|
||||||
display_exists
|
display_exists,
|
||||||
|
whenH (isJust apiError)
|
||||||
|
(alert_notification (fromMaybe "" apiError))
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
, tr_
|
, tr_
|
||||||
[ td_ [ label [ for "url" ] [ text "URL" ] ]
|
[ td_ [ label [ for "url" ] [ text "URL" ] ]
|
||||||
, td_ [ input [ type_ InputUrl , id_ "url", class_ "w-100 mv1" , required true, name "url", autofocus (null bm.url)
|
, td_ [ input [ type_ InputUrl , id "url", class_ "w-100 mv1" , required true, name "url", autofocus (null bm.url)
|
||||||
, value (edit_bm.url) , onValueChange (editField Eurl)] ]
|
, value (edit_bm.url) , onValueChange (editField Eurl)] ]
|
||||||
]
|
]
|
||||||
, tr_
|
, tr_
|
||||||
[ td_ [ label [ for "title" ] [ text "title" ] ]
|
[ td_ [ label [ for "title" ] [ text "title" ] ]
|
||||||
, td [class_ "flex"]
|
, td [class_ "flex"]
|
||||||
[ input [ type_ InputText , id_ "title", class_ "w-100 mv1 flex-auto" , name "title" , value (edit_bm.title) , onValueChange (editField Etitle)]
|
[ input [ type_ InputText , id "title", class_ "w-100 mv1 flex-auto" , name "title" , value (edit_bm.title) , onValueChange (editField Etitle)]
|
||||||
, button [ disabled s.loading, type_ ButtonButton, onClick \_ -> BLookupTitle, class_ ("ml2 input-reset ba b--navy pointer f6 di dim pa1 ma1 mr0 " <> guard s.loading "bg-light-silver") ] [ text "fetch" ]
|
, button [ disabled s.loading, type_ ButtonButton, onClick \_ -> BLookupTitle, class_ ("ml2 input-reset ba b--navy pointer f6 di dim pa1 ma1 mr0 " <> guard s.loading "bg-light-silver") ] [ text "fetch" ]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
, tr_
|
, tr_
|
||||||
[ td_ [ label [ for "description" ] [ text "description" ] ]
|
[ td_ [ label [ for "description" ] [ text "description" ] ]
|
||||||
, td_ [ textarea [ class_ "w-100 mt1 mid-gray" , id_ "description", name "description", rows 4
|
, td_ [ textarea [ class_ "w-100 mt1 mid-gray" , id "description", name "description", rows 4
|
||||||
, value (edit_bm.description) , onValueChange (editField Edescription)] ]
|
, value (edit_bm.description) , onValueChange (editField Edescription)] ]
|
||||||
]
|
]
|
||||||
, tr_
|
, tr_
|
||||||
[ td_ [ label [ for "tags" ] [ text "tags" ] ]
|
[ td_ [ label [ for "tags" ] [ text "tags" ] ]
|
||||||
, td_ [ input [ type_ InputText , id_ "tags", class_ "w-100 mv1" , name "tags", autocomplete false, attr "autocapitalize" "off", autofocus (not $ null bm.url)
|
, td_ [ input [ type_ InputText , id "tags", class_ "w-100 mv1" , name "tags", autocomplete false, attr "autocapitalize" "off", autofocus (not $ null bm.url)
|
||||||
, value (edit_bm.tags) , onValueChange (editField Etags)] ]
|
, value (edit_bm.tags) , onValueChange (editField Etags)] ]
|
||||||
]
|
]
|
||||||
, tr_
|
, tr_
|
||||||
[ td_ [ label [ for "private" ] [ text "private" ] ]
|
[ td_ [ label [ for "private" ] [ text "private" ] ]
|
||||||
, td_ [ input [ type_ InputCheckbox , id_ "private", class_ "private pointer" , name "private"
|
, td_ [ input [ type_ InputCheckbox , id "private", class_ "private pointer" , name "private"
|
||||||
, checked (edit_bm.private) , onChecked (editField Eprivate)] ]
|
, checked (edit_bm.private) , onChecked (editField Eprivate)] ]
|
||||||
]
|
]
|
||||||
, tr_
|
, tr_
|
||||||
[ td_ [ label [ for "toread" ] [ text "read later" ] ]
|
[ td_ [ label [ for "toread" ] [ text "read later" ] ]
|
||||||
, td_ [ input [ type_ InputCheckbox , id_ "toread", class_ "toread pointer" , name "toread"
|
, td_ [ input [ type_ InputCheckbox , id "toread", class_ "toread pointer" , name "toread"
|
||||||
, checked (edit_bm.toread) , onChecked (editField Etoread)] ]
|
, checked (edit_bm.toread) , onChecked (editField Etoread)] ]
|
||||||
]
|
]
|
||||||
, tr_
|
, tr_
|
||||||
|
@ -146,6 +152,9 @@ addbmark b' =
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
alert_notification alert_text _ =
|
||||||
|
div [ class_ "alert alert-err" ] [ text alert_text ]
|
||||||
|
|
||||||
display_destroyed _ = p [ class_ "red"] [text "you killed this bookmark"]
|
display_destroyed _ = p [ class_ "red"] [text "you killed this bookmark"]
|
||||||
|
|
||||||
editField :: forall a. (a -> EditField) -> a -> BAction
|
editField :: forall a. (a -> EditField) -> a -> BAction
|
||||||
|
@ -186,8 +195,10 @@ addbmark b' =
|
||||||
handleAction (BEditSubmit e) = do
|
handleAction (BEditSubmit e) = do
|
||||||
liftEffect (preventDefault e)
|
liftEffect (preventDefault e)
|
||||||
edit_bm <- use _edit_bm
|
edit_bm <- use _edit_bm
|
||||||
|
_apiError .= Nothing
|
||||||
H.liftAff (editBookmark edit_bm) >>= case _ of
|
H.liftAff (editBookmark edit_bm) >>= case _ of
|
||||||
Left affErr -> do
|
Left affErr -> do
|
||||||
|
_apiError .= Just (printError affErr)
|
||||||
liftEffect $ log (printError affErr)
|
liftEffect $ log (printError affErr)
|
||||||
Right { status: StatusCode s } | s >= 200 && s < 300 -> do
|
Right { status: StatusCode s } | s >= 200 && s < 300 -> do
|
||||||
_bm .= edit_bm
|
_bm .= edit_bm
|
||||||
|
@ -204,4 +215,5 @@ addbmark b' =
|
||||||
Nothing -> setHref org loc
|
Nothing -> setHref org loc
|
||||||
_ -> liftEffect $ closeWindow =<< window
|
_ -> liftEffect $ closeWindow =<< window
|
||||||
Right res -> do
|
Right res -> do
|
||||||
|
_apiError .= Just (res.body)
|
||||||
liftEffect $ log (res.body)
|
liftEffect $ log (res.body)
|
||||||
|
|
|
@ -2,24 +2,29 @@ module Component.BMark where
|
||||||
|
|
||||||
import Prelude hiding (div)
|
import Prelude hiding (div)
|
||||||
|
|
||||||
|
import Affjax (printError)
|
||||||
|
import Affjax.StatusCode (StatusCode(..))
|
||||||
import App (StarAction(..), destroy, editBookmark, markRead, toggleStar, lookupTitle)
|
import App (StarAction(..), destroy, editBookmark, markRead, toggleStar, lookupTitle)
|
||||||
import Component.Markdown as Markdown
|
import Component.Markdown as Markdown
|
||||||
import Data.Const (Const)
|
import Data.Const (Const)
|
||||||
|
import Data.Either (Either(..))
|
||||||
import Data.Lens (Lens', lens, use, (%=), (.=))
|
import Data.Lens (Lens', lens, use, (%=), (.=))
|
||||||
import Data.Maybe (Maybe(..), fromMaybe, isJust)
|
import Data.Maybe (Maybe(..), fromMaybe, isJust)
|
||||||
import Data.Monoid (guard)
|
import Data.Monoid (guard)
|
||||||
import Data.Nullable (toMaybe)
|
import Data.Nullable (toMaybe)
|
||||||
import Data.String (null, split, take, replaceAll) as S
|
import Data.String (null, split, take, replaceAll) as S
|
||||||
import Data.String.Pattern (Pattern(..), Replacement(..))
|
import Data.String.Pattern (Pattern(..), Replacement(..))
|
||||||
import Type.Proxy (Proxy(..))
|
|
||||||
import Effect.Aff (Aff)
|
import Effect.Aff (Aff)
|
||||||
|
import Effect.Class (liftEffect)
|
||||||
|
import Effect.Class.Console (log)
|
||||||
import Globals (app', setFocus, toLocaleDateString)
|
import Globals (app', setFocus, toLocaleDateString)
|
||||||
import Halogen as H
|
import Halogen as H
|
||||||
import Halogen.HTML (a, br_, button, div, div_, form, input, label, span, text, textarea)
|
import Halogen.HTML (a, br_, button, div, div_, form, input, label, span, text, textarea)
|
||||||
import Halogen.HTML as HH
|
import Halogen.HTML as HH
|
||||||
import Halogen.HTML.Events (onSubmit, onValueChange, onChecked, onClick)
|
import Halogen.HTML.Events (onSubmit, onValueChange, onChecked, onClick)
|
||||||
import Halogen.HTML.Properties (ButtonType(..), InputType(..), autocomplete, checked, disabled, for, href, id_, name, required, rows, target, title, type_, value)
|
import Halogen.HTML.Properties (ButtonType(..), InputType(..), autocomplete, checked, disabled, for, href, id, name, required, rows, target, title, type_, value)
|
||||||
import Model (Bookmark)
|
import Model (Bookmark)
|
||||||
|
import Type.Proxy (Proxy(..))
|
||||||
import Util (attr, class_, fromNullableStr, ifElseH, whenH, whenA)
|
import Util (attr, class_, fromNullableStr, ifElseH, whenH, whenA)
|
||||||
import Web.Event.Event (Event, preventDefault)
|
import Web.Event.Event (Event, preventDefault)
|
||||||
|
|
||||||
|
@ -55,6 +60,7 @@ type BState =
|
||||||
, deleteAsk:: Boolean
|
, deleteAsk:: Boolean
|
||||||
, edit :: Boolean
|
, edit :: Boolean
|
||||||
, loading :: Boolean
|
, loading :: Boolean
|
||||||
|
, apiError :: Maybe String
|
||||||
}
|
}
|
||||||
|
|
||||||
_bm :: Lens' BState Bookmark
|
_bm :: Lens' BState Bookmark
|
||||||
|
@ -66,6 +72,9 @@ _edit_bm = lens _.edit_bm (_ { edit_bm = _ })
|
||||||
_edit :: Lens' BState Boolean
|
_edit :: Lens' BState Boolean
|
||||||
_edit = lens _.edit (_ { edit = _ })
|
_edit = lens _.edit (_ { edit = _ })
|
||||||
|
|
||||||
|
_apiError :: Lens' BState (Maybe String)
|
||||||
|
_apiError = lens _.apiError (_ { apiError = _ })
|
||||||
|
|
||||||
_markdown = Proxy :: Proxy "markdown"
|
_markdown = Proxy :: Proxy "markdown"
|
||||||
|
|
||||||
type ChildSlots =
|
type ChildSlots =
|
||||||
|
@ -88,11 +97,12 @@ bmark b' =
|
||||||
, deleteAsk: false
|
, deleteAsk: false
|
||||||
, edit: false
|
, edit: false
|
||||||
, loading: false
|
, loading: false
|
||||||
|
, apiError: Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
render :: BState -> H.ComponentHTML BAction ChildSlots Aff
|
render :: BState -> H.ComponentHTML BAction ChildSlots Aff
|
||||||
render s@{ bm, edit_bm } =
|
render s@{ bm, edit_bm, apiError } =
|
||||||
div [ id_ (show bm.bid) , class_ ("bookmark w-100 mw7 pa1 mb3" <> guard bm.private " private")] $
|
div [ id (show bm.bid) , class_ ("bookmark w-100 mw7 pa1 mb3" <> guard bm.private " private")] $
|
||||||
[ whenH app.dat.isowner
|
[ whenH app.dat.isowner
|
||||||
star
|
star
|
||||||
, ifElseH s.edit
|
, ifElseH s.edit
|
||||||
|
@ -151,7 +161,9 @@ bmark b' =
|
||||||
|
|
||||||
display_edit _ =
|
display_edit _ =
|
||||||
div [ class_ "edit_bookmark_form pa2 pt0 bg-white" ] $
|
div [ class_ "edit_bookmark_form pa2 pt0 bg-white" ] $
|
||||||
[ form [ onSubmit BEditSubmit ]
|
[ whenH (isJust apiError)
|
||||||
|
(alert_notification (fromMaybe "" apiError))
|
||||||
|
, form [ onSubmit BEditSubmit ]
|
||||||
[ div_ [ text "url" ]
|
[ div_ [ text "url" ]
|
||||||
, input [ type_ InputUrl , class_ "url w-100 mb2 pt1 edit_form_input" , required true , name "url"
|
, input [ type_ InputUrl , class_ "url w-100 mb2 pt1 edit_form_input" , required true , name "url"
|
||||||
, value (edit_bm.url) , onValueChange (editField Eurl) ]
|
, value (edit_bm.url) , onValueChange (editField Eurl) ]
|
||||||
|
@ -164,19 +176,19 @@ bmark b' =
|
||||||
, div_ [ text "description" ]
|
, div_ [ text "description" ]
|
||||||
, textarea [ class_ "description w-100 mb1 pt1 edit_form_input" , name "description", rows 5
|
, textarea [ class_ "description w-100 mb1 pt1 edit_form_input" , name "description", rows 5
|
||||||
, value (edit_bm.description) , onValueChange (editField Edescription) ]
|
, value (edit_bm.description) , onValueChange (editField Edescription) ]
|
||||||
, div [ id_ "tags_input_box"]
|
, div [ id "tags_input_box"]
|
||||||
[ div_ [ text "tags" ]
|
[ div_ [ text "tags" ]
|
||||||
, input [ id_ (tagid edit_bm), type_ InputText , class_ "tags w-100 mb1 pt1 edit_form_input" , name "tags"
|
, input [ id (tagid edit_bm), type_ InputText , class_ "tags w-100 mb1 pt1 edit_form_input" , name "tags"
|
||||||
, autocomplete false, attr "autocapitalize" "off"
|
, autocomplete false, attr "autocapitalize" "off"
|
||||||
, value (edit_bm.tags) , onValueChange (editField Etags) ]
|
, value (edit_bm.tags) , onValueChange (editField Etags) ]
|
||||||
]
|
]
|
||||||
, div [ class_ "edit_form_checkboxes mv3"]
|
, div [ class_ "edit_form_checkboxes mv3"]
|
||||||
[ input [ type_ InputCheckbox , class_ "private pointer" , id_ "edit_private", name "private"
|
[ input [ type_ InputCheckbox , class_ "private pointer" , id "edit_private", name "private"
|
||||||
, checked (edit_bm.private) , onChecked (editField Eprivate) ]
|
, checked (edit_bm.private) , onChecked (editField Eprivate) ]
|
||||||
, text " "
|
, text " "
|
||||||
, label [ for "edit_private" , class_ "mr2" ] [ text "private" ]
|
, label [ for "edit_private" , class_ "mr2" ] [ text "private" ]
|
||||||
, text " "
|
, text " "
|
||||||
, input [ type_ InputCheckbox , class_ "toread pointer" , id_ "edit_toread", name "toread"
|
, input [ type_ InputCheckbox , class_ "toread pointer" , id "edit_toread", name "toread"
|
||||||
, checked (edit_bm.toread) , onChecked (editField Etoread) ]
|
, checked (edit_bm.toread) , onChecked (editField Etoread) ]
|
||||||
, text " "
|
, text " "
|
||||||
, label [ for "edit_toread" ] [ text "to-read" ]
|
, label [ for "edit_toread" ] [ text "to-read" ]
|
||||||
|
@ -188,6 +200,8 @@ bmark b' =
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
alert_notification alert_text _ =
|
||||||
|
div [ class_ "alert alert-err" ] [ text alert_text ]
|
||||||
|
|
||||||
editField :: forall a. (a -> EditField) -> a -> BAction
|
editField :: forall a. (a -> EditField) -> a -> BAction
|
||||||
editField f = BEditField <<< f
|
editField f = BEditField <<< f
|
||||||
|
@ -228,6 +242,7 @@ bmark b' =
|
||||||
bm <- use _bm
|
bm <- use _bm
|
||||||
_edit_bm .= bm
|
_edit_bm .= bm
|
||||||
_edit .= e
|
_edit .= e
|
||||||
|
_apiError .= Nothing
|
||||||
H.liftEffect $
|
H.liftEffect $
|
||||||
when e
|
when e
|
||||||
(setFocus (tagid bm))
|
(setFocus (tagid bm))
|
||||||
|
@ -256,7 +271,15 @@ bmark b' =
|
||||||
handleAction (BEditSubmit e) = do
|
handleAction (BEditSubmit e) = do
|
||||||
H.liftEffect (preventDefault e)
|
H.liftEffect (preventDefault e)
|
||||||
edit_bm <- use _edit_bm
|
edit_bm <- use _edit_bm
|
||||||
|
_apiError .= Nothing
|
||||||
let edit_bm' = edit_bm { tags = S.replaceAll (Pattern ",") (Replacement " ") edit_bm.tags }
|
let edit_bm' = edit_bm { tags = S.replaceAll (Pattern ",") (Replacement " ") edit_bm.tags }
|
||||||
void $ H.liftAff (editBookmark edit_bm')
|
H.liftAff (editBookmark edit_bm') >>= case _ of
|
||||||
|
Left affErr -> do
|
||||||
|
_apiError .= Just (printError affErr)
|
||||||
|
liftEffect $ log (printError affErr)
|
||||||
|
Right { status: StatusCode s } | s >= 200 && s < 300 -> do
|
||||||
_bm .= edit_bm'
|
_bm .= edit_bm'
|
||||||
_edit .= false
|
_edit .= false
|
||||||
|
Right res -> do
|
||||||
|
_apiError .= Just (res.body)
|
||||||
|
liftEffect $ log (res.body)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import Globals (app', mmoment8601)
|
||||||
import Halogen as H
|
import Halogen as H
|
||||||
import Halogen.HTML (a, br_, div, text)
|
import Halogen.HTML (a, br_, div, text)
|
||||||
import Halogen.HTML as HH
|
import Halogen.HTML as HH
|
||||||
import Halogen.HTML.Properties (href, id_, title)
|
import Halogen.HTML.Properties (href, id, title)
|
||||||
import Model (Note, NoteSlug)
|
import Model (Note, NoteSlug)
|
||||||
import Util (class_, fromNullableStr)
|
import Util (class_, fromNullableStr)
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ nlist st' =
|
||||||
HH.div_ (map renderNote notes)
|
HH.div_ (map renderNote notes)
|
||||||
where
|
where
|
||||||
renderNote note =
|
renderNote note =
|
||||||
div [ id_ (show note.id)
|
div [ id (show note.id)
|
||||||
, class_ ("note w-100 mw7 pa1 mb2"
|
, class_ ("note w-100 mw7 pa1 mb2"
|
||||||
<> if note.shared then "" else " private")] $
|
<> if note.shared then "" else " private")] $
|
||||||
[ div [ class_ "display" ] $
|
[ div [ class_ "display" ] $
|
||||||
|
|
|
@ -2,12 +2,15 @@ module Component.NNote where
|
||||||
|
|
||||||
import Prelude hiding (div)
|
import Prelude hiding (div)
|
||||||
|
|
||||||
|
import Affjax (printError)
|
||||||
|
import Affjax.StatusCode (StatusCode(..))
|
||||||
import App (destroyNote, editNote)
|
import App (destroyNote, editNote)
|
||||||
import Component.Markdown as Markdown
|
import Component.Markdown as Markdown
|
||||||
import Data.Array (drop, foldMap)
|
import Data.Array (drop, foldMap)
|
||||||
|
import Data.Either (Either(..))
|
||||||
import Data.Foldable (for_)
|
import Data.Foldable (for_)
|
||||||
import Data.Lens (Lens', lens, use, (%=), (.=))
|
import Data.Lens (Lens', lens, use, (%=), (.=))
|
||||||
import Data.Maybe (Maybe(..), isJust, maybe)
|
import Data.Maybe (Maybe(..), fromMaybe, isJust, maybe)
|
||||||
import Data.Monoid (guard)
|
import Data.Monoid (guard)
|
||||||
import Data.String (null, split) as S
|
import Data.String (null, split) as S
|
||||||
import Data.String (null, stripPrefix)
|
import Data.String (null, stripPrefix)
|
||||||
|
@ -15,12 +18,13 @@ import Data.String.Pattern (Pattern(..))
|
||||||
import Data.Tuple (fst, snd)
|
import Data.Tuple (fst, snd)
|
||||||
import Effect.Aff (Aff)
|
import Effect.Aff (Aff)
|
||||||
import Effect.Class (liftEffect)
|
import Effect.Class (liftEffect)
|
||||||
|
import Effect.Console (log)
|
||||||
import Globals (app', mmoment8601, setFocus, closeWindow)
|
import Globals (app', mmoment8601, setFocus, closeWindow)
|
||||||
import Halogen as H
|
import Halogen as H
|
||||||
import Halogen.HTML (br_, button, div, form, input, label, p, span, text, textarea)
|
import Halogen.HTML (br_, button, div, form, input, label, p, span, text, textarea)
|
||||||
import Halogen.HTML as HH
|
import Halogen.HTML as HH
|
||||||
import Halogen.HTML.Events (onChecked, onClick, onSubmit, onValueChange)
|
import Halogen.HTML.Events (onChecked, onClick, onSubmit, onValueChange)
|
||||||
import Halogen.HTML.Properties (ButtonType(..), InputType(..), autofocus, checked, for, id_, name, rows, title, type_, value)
|
import Halogen.HTML.Properties (ButtonType(..), InputType(..), autofocus, checked, for, id, name, rows, title, type_, value)
|
||||||
import Model (Note)
|
import Model (Note)
|
||||||
import Type.Proxy (Proxy(..))
|
import Type.Proxy (Proxy(..))
|
||||||
import Util (_curQuerystring, _doc, _loc, _lookupQueryStringValue, class_, fromNullableStr, ifElseH, whenH)
|
import Util (_curQuerystring, _doc, _loc, _lookupQueryStringValue, class_, fromNullableStr, ifElseH, whenH)
|
||||||
|
@ -43,6 +47,7 @@ type NState =
|
||||||
, deleteAsk :: Boolean
|
, deleteAsk :: Boolean
|
||||||
, edit :: Boolean
|
, edit :: Boolean
|
||||||
, destroyed :: Boolean
|
, destroyed :: Boolean
|
||||||
|
, apiError :: Maybe String
|
||||||
}
|
}
|
||||||
|
|
||||||
_note :: Lens' NState Note
|
_note :: Lens' NState Note
|
||||||
|
@ -54,6 +59,9 @@ _edit_note = lens _.edit_note (_ { edit_note = _ })
|
||||||
_edit :: Lens' NState Boolean
|
_edit :: Lens' NState Boolean
|
||||||
_edit = lens _.edit (_ { edit = _ })
|
_edit = lens _.edit (_ { edit = _ })
|
||||||
|
|
||||||
|
_apiError :: Lens' NState (Maybe String)
|
||||||
|
_apiError = lens _.apiError (_ { apiError = _ })
|
||||||
|
|
||||||
-- | FormField Edits
|
-- | FormField Edits
|
||||||
data EditField
|
data EditField
|
||||||
= Etitle String
|
= Etitle String
|
||||||
|
@ -83,10 +91,11 @@ nnote st' =
|
||||||
, deleteAsk: false
|
, deleteAsk: false
|
||||||
, edit: note'.id <= 0
|
, edit: note'.id <= 0
|
||||||
, destroyed: false
|
, destroyed: false
|
||||||
|
, apiError: Nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
render :: NState -> H.ComponentHTML NAction ChildSlots Aff
|
render :: NState -> H.ComponentHTML NAction ChildSlots Aff
|
||||||
render st@{ note, edit_note } =
|
render st@{ note, edit_note, apiError } =
|
||||||
ifElseH st.destroyed
|
ifElseH st.destroyed
|
||||||
display_destroyed
|
display_destroyed
|
||||||
(const (ifElseH st.edit
|
(const (ifElseH st.edit
|
||||||
|
@ -95,7 +104,7 @@ nnote st' =
|
||||||
where
|
where
|
||||||
|
|
||||||
renderNote _ =
|
renderNote _ =
|
||||||
div [ id_ (show note.id) , class_ ("note w-100 mw7 pa1 mb2")] $
|
div [ id (show note.id) , class_ ("note w-100 mw7 pa1 mb2")] $
|
||||||
[ div [ class_ "display" ] $
|
[ div [ class_ "display" ] $
|
||||||
[ div [ class_ ("link f5 lh-title")]
|
[ div [ class_ ("link f5 lh-title")]
|
||||||
[ text $ if S.null note.title then "[no title]" else note.title ]
|
[ text $ if S.null note.title then "[no title]" else note.title ]
|
||||||
|
@ -127,24 +136,26 @@ nnote st' =
|
||||||
|
|
||||||
renderNote_edit _ =
|
renderNote_edit _ =
|
||||||
form [ onSubmit NEditSubmit ]
|
form [ onSubmit NEditSubmit ]
|
||||||
[ p [ class_ "mt2 mb1"] [ text "title:" ]
|
[ whenH (isJust apiError)
|
||||||
|
(alert_notification (fromMaybe "" apiError))
|
||||||
|
, p [ class_ "mt2 mb1"] [ text "title:" ]
|
||||||
, input [ type_ InputText , class_ "title w-100 mb1 pt1 edit_form_input" , name "title"
|
, input [ type_ InputText , class_ "title w-100 mb1 pt1 edit_form_input" , name "title"
|
||||||
, value (edit_note.title) , onValueChange (editField Etitle), autofocus (null edit_note.title)
|
, value (edit_note.title) , onValueChange (editField Etitle), autofocus (null edit_note.title)
|
||||||
]
|
]
|
||||||
, br_
|
, br_
|
||||||
, p [ class_ "mt2 mb1"] [ text "description:" ]
|
, p [ class_ "mt2 mb1"] [ text "description:" ]
|
||||||
, textarea [ id_ (notetextid edit_note), class_ "description w-100 mb1 pt1 edit_form_input" , name "text", rows 25
|
, textarea [ id (notetextid edit_note), class_ "description w-100 mb1 pt1 edit_form_input" , name "text", rows 25
|
||||||
, value (edit_note.text) , onValueChange (editField Etext)
|
, value (edit_note.text) , onValueChange (editField Etext)
|
||||||
]
|
]
|
||||||
, div [ class_ "edit_form_checkboxes mb3"]
|
, div [ class_ "edit_form_checkboxes mb3"]
|
||||||
[ input [ type_ InputCheckbox , class_ "is-markdown pointer" , id_ "edit_ismarkdown", name "ismarkdown"
|
[ input [ type_ InputCheckbox , class_ "is-markdown pointer" , id "edit_ismarkdown", name "ismarkdown"
|
||||||
, checked (edit_note.isMarkdown) , onChecked (editField EisMarkdown) ]
|
, checked (edit_note.isMarkdown) , onChecked (editField EisMarkdown) ]
|
||||||
, text " "
|
, text " "
|
||||||
, label [ for "edit_ismarkdown" , class_ "mr2" ] [ text "use markdown?" ]
|
, label [ for "edit_ismarkdown" , class_ "mr2" ] [ text "use markdown?" ]
|
||||||
, br_
|
, br_
|
||||||
]
|
]
|
||||||
, div [ class_ "edit_form_checkboxes mb3"]
|
, div [ class_ "edit_form_checkboxes mb3"]
|
||||||
[ input [ type_ InputCheckbox , class_ "is-markdown pointer" , id_ "edit_shared", name "shared"
|
[ input [ type_ InputCheckbox , class_ "is-markdown pointer" , id "edit_shared", name "shared"
|
||||||
, checked (edit_note.shared) , onChecked (editField Eshared) ]
|
, checked (edit_note.shared) , onChecked (editField Eshared) ]
|
||||||
, text " "
|
, text " "
|
||||||
, label [ for "edit_shared" , class_ "mr2" ] [ text "public?" ]
|
, label [ for "edit_shared" , class_ "mr2" ] [ text "public?" ]
|
||||||
|
@ -163,6 +174,9 @@ nnote st' =
|
||||||
|
|
||||||
display_destroyed _ = p [ class_ "red"] [text "you killed this note"]
|
display_destroyed _ = p [ class_ "red"] [text "you killed this note"]
|
||||||
|
|
||||||
|
alert_notification alert_text _ =
|
||||||
|
div [ class_ "alert alert-err" ] [ text alert_text ]
|
||||||
|
|
||||||
mmoment n = mmoment8601 n.created
|
mmoment n = mmoment8601 n.created
|
||||||
editField :: forall a. (a -> EditField) -> a -> NAction
|
editField :: forall a. (a -> EditField) -> a -> NAction
|
||||||
editField f = NEditField <<< f
|
editField f = NEditField <<< f
|
||||||
|
@ -209,8 +223,12 @@ nnote st' =
|
||||||
handleAction (NEditSubmit e) = do
|
handleAction (NEditSubmit e) = do
|
||||||
H.liftEffect (preventDefault e)
|
H.liftEffect (preventDefault e)
|
||||||
edit_note <- use _edit_note
|
edit_note <- use _edit_note
|
||||||
res' <- H.liftAff (editNote edit_note)
|
_apiError .= Nothing
|
||||||
for_ res' \_ -> do
|
H.liftAff (editNote edit_note) >>= case _ of
|
||||||
|
Left affErr -> do
|
||||||
|
_apiError .= Just (printError affErr)
|
||||||
|
liftEffect $ log (printError affErr)
|
||||||
|
Right { status: StatusCode s } | s >= 200 && s < 300 -> do
|
||||||
qs <- liftEffect _curQuerystring
|
qs <- liftEffect _curQuerystring
|
||||||
doc <- liftEffect $ _doc
|
doc <- liftEffect $ _doc
|
||||||
ref <- liftEffect $ referrer doc
|
ref <- liftEffect $ referrer doc
|
||||||
|
@ -227,3 +245,6 @@ nnote st' =
|
||||||
else do
|
else do
|
||||||
_note .= edit_note
|
_note .= edit_note
|
||||||
_edit .= false
|
_edit .= false
|
||||||
|
Right res -> do
|
||||||
|
_apiError .= Just (res.body)
|
||||||
|
liftEffect $ log (res.body)
|
||||||
|
|
|
@ -151,6 +151,11 @@ label {
|
||||||
.alert {
|
.alert {
|
||||||
background: #ced;
|
background: #ced;
|
||||||
border: 1px solid #acc;
|
border: 1px solid #acc;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
.alert.alert-err {
|
||||||
|
background-color: #ffdfdf
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit_bookmark_form {
|
.edit_bookmark_form {
|
||||||
|
|
|
@ -25,6 +25,9 @@ textarea {
|
||||||
#addForm .alert {
|
#addForm .alert {
|
||||||
margin-top: -6px;
|
margin-top: -6px;
|
||||||
}
|
}
|
||||||
|
.alert.alert-err {
|
||||||
|
background-color: #ffdfdf
|
||||||
|
}
|
||||||
form label {
|
form label {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
2
static/js/app.min.js
vendored
2
static/js/app.min.js
vendored
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
Loading…
Reference in a new issue