mirror of
https://github.com/aelve/guide.git
synced 2024-12-23 21:02:13 +03:00
Allow editing of pro/con text
This commit is contained in:
parent
187ce0abe6
commit
c372cc48ca
128
src/Main.hs
128
src/Main.hs
@ -44,18 +44,29 @@ type UID = Int
|
||||
randomUID :: MonadIO m => m UID
|
||||
randomUID = liftIO $ randomRIO (0, 10^(9::Int))
|
||||
|
||||
data ProCon = ProCon {
|
||||
_proConId :: UID,
|
||||
_proConText :: Text }
|
||||
|
||||
makeLenses ''ProCon
|
||||
|
||||
data ItemKind = HackageLibrary | Library | Unknown
|
||||
|
||||
data Item = Item {
|
||||
_itemId :: UID,
|
||||
_name :: Text,
|
||||
_pros :: [Text],
|
||||
_cons :: [Text],
|
||||
_pros :: [ProCon],
|
||||
_cons :: [ProCon],
|
||||
_link :: Maybe Text,
|
||||
_kind :: ItemKind }
|
||||
|
||||
makeLenses ''Item
|
||||
|
||||
proConById :: UID -> Lens' Item ProCon
|
||||
proConById uid = singular $
|
||||
(pros.each . filtered ((== uid) . view proConId)) `failing`
|
||||
(cons.each . filtered ((== uid) . view proConId))
|
||||
|
||||
data Category = Category {
|
||||
_catId :: UID,
|
||||
_title :: Text,
|
||||
@ -90,15 +101,17 @@ sampleState = S {
|
||||
Item {
|
||||
_itemId = 2,
|
||||
_name = "lens",
|
||||
_pros = ["the standard lenses library", "batteries included"],
|
||||
_cons = ["huge"],
|
||||
_pros = [ProCon 3 "the standard lenses library",
|
||||
ProCon 4 "batteries included"],
|
||||
_cons = [ProCon 5 "huge"],
|
||||
_link = Nothing,
|
||||
_kind = HackageLibrary },
|
||||
Item {
|
||||
_itemId = 3,
|
||||
_itemId = 6,
|
||||
_name = "microlens",
|
||||
_pros = ["very small", "good for libraries"],
|
||||
_cons = ["doesn't have advanced features"],
|
||||
_pros = [ProCon 7 "very small",
|
||||
ProCon 8 "good for libraries"],
|
||||
_cons = [ProCon 9 "doesn't have advanced features"],
|
||||
_link = Nothing,
|
||||
_kind = HackageLibrary }
|
||||
] }
|
||||
@ -153,21 +166,23 @@ main = runSpock 8080 $ spockT id $ do
|
||||
-- already deleted)
|
||||
withS $
|
||||
categoryById catId' . items %= (++ [newItem])
|
||||
lucid $ renderItem NonEditable newItem
|
||||
lucid $ renderItem Normal newItem
|
||||
|
||||
-- Add a pro (argument in favor of a library).
|
||||
Spock.post ("/item" <//> var <//> "pros/add") $ \itemId' -> do
|
||||
content <- param' "content"
|
||||
content <- param' "content"
|
||||
uid <- randomUID
|
||||
changedItem <- withS $ do
|
||||
itemById itemId' . pros %= (++ [content])
|
||||
itemById itemId' . pros %= (++ [ProCon uid content])
|
||||
use (itemById itemId')
|
||||
lucid $ renderItem Editable changedItem
|
||||
|
||||
-- Add a con (argument against a library).
|
||||
Spock.post ("/item" <//> var <//> "cons/add") $ \itemId' -> do
|
||||
content <- param' "content"
|
||||
content <- param' "content"
|
||||
uid <- randomUID
|
||||
changedItem <- withS $ do
|
||||
itemById itemId' . cons %= (++ [content])
|
||||
itemById itemId' . cons %= (++ [ProCon uid content])
|
||||
use (itemById itemId')
|
||||
lucid $ renderItem Editable changedItem
|
||||
|
||||
@ -193,13 +208,34 @@ main = runSpock 8080 $ spockT id $ do
|
||||
-- Return rendered item the way it should normally look.
|
||||
Spock.get ("/item" <//> var <//> "render-normal") $ \itemId' -> do
|
||||
item <- withS $ use (itemById itemId')
|
||||
lucid $ renderItem NonEditable item
|
||||
lucid $ renderItem Normal item
|
||||
|
||||
-- Return rendered item the way it should look when it's being edited.
|
||||
-- Return rendered item the way it should look when it's editable.
|
||||
Spock.get ("/item" <//> var <//> "render-edit") $ \itemId' -> do
|
||||
item <- withS $ use (itemById itemId')
|
||||
lucid $ renderItem Editable item
|
||||
|
||||
-- Return rendered pro/con the way it should normally look.
|
||||
Spock.get ("/item" <//> var <//> "pro-con" <//> var <//> "render-normal") $
|
||||
\itemId' proConId' -> do
|
||||
thing <- withS $ use (itemById itemId' . proConById proConId')
|
||||
lucid $ renderProCon Editable itemId' thing
|
||||
|
||||
-- Return rendered pro/con the way it should look when it's being edited.
|
||||
Spock.get ("/item" <//> var <//> "pro-con" <//> var <//> "render-edit") $
|
||||
\itemId' proConId' -> do
|
||||
thing <- withS $ use (itemById itemId' . proConById proConId')
|
||||
lucid $ renderProCon InEdit itemId' thing
|
||||
|
||||
-- Change a pro/con.
|
||||
Spock.post ("/item" <//> var <//> "pro-con" <//> var <//> "set") $
|
||||
\itemId' proConId' -> do
|
||||
content <- param' "content"
|
||||
changedThing <- withS $ do
|
||||
itemById itemId' . proConById proConId' . proConText .= content
|
||||
use (itemById itemId' . proConById proConId')
|
||||
lucid $ renderProCon Editable itemId' changedThing
|
||||
|
||||
renderRoot :: S -> HtmlT IO ()
|
||||
renderRoot s = do
|
||||
includeJS "https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"
|
||||
@ -237,7 +273,7 @@ renderCategory category =
|
||||
div_ [id_ (tshow (category^.catId))] $ do
|
||||
renderCategoryHeading category
|
||||
itemsNode <- div_ [class_ "items"] $ do
|
||||
mapM_ (renderItem NonEditable) (category^.items)
|
||||
mapM_ (renderItem Normal) (category^.items)
|
||||
thisNode
|
||||
let handler = js_addLibrary (itemsNode, category^.catId, js_this_value)
|
||||
input_ [type_ "text", placeholder_ "new item", submitFunc handler]
|
||||
@ -254,25 +290,27 @@ renderItem editable item =
|
||||
h3_ $ do
|
||||
itemHeader
|
||||
case editable of
|
||||
NonEditable -> textButton "edit" $
|
||||
Normal -> textButton "edit" $
|
||||
js_enableItemEdit (itemNode, item^.itemId)
|
||||
Editable -> textButton "edit off" $
|
||||
js_disableItemEdit (itemNode, item^.itemId)
|
||||
div_ [class_ "pros-cons"] $ do
|
||||
div_ [class_ "pros"] $ do
|
||||
p_ "Pros:"
|
||||
ul_ $ mapM_ (li_ . toHtml) (item^.pros)
|
||||
case editable of
|
||||
NonEditable -> return ()
|
||||
Normal ->
|
||||
ul_ $ mapM_ (renderProCon Normal (item^.itemId)) (item^.pros)
|
||||
Editable -> do
|
||||
ul_ $ mapM_ (renderProCon Editable (item^.itemId)) (item^.pros)
|
||||
let handler = js_addPros (itemNode, item^.itemId, js_this_value)
|
||||
input_ [type_ "text", placeholder_ "add pros", submitFunc handler]
|
||||
div_ [class_ "cons"] $ do
|
||||
p_ "Cons:"
|
||||
ul_ $ mapM_ (li_ . toHtml) (item^.cons)
|
||||
case editable of
|
||||
NonEditable -> return ()
|
||||
Normal ->
|
||||
ul_ $ mapM_ (renderProCon Normal (item^.itemId)) (item^.cons)
|
||||
Editable -> do
|
||||
ul_ $ mapM_ (renderProCon Editable (item^.itemId)) (item^.cons)
|
||||
let handler = js_addCons (itemNode, item^.itemId, js_this_value)
|
||||
input_ [type_ "text", placeholder_ "add cons", submitFunc handler]
|
||||
where
|
||||
@ -285,6 +323,21 @@ renderItem editable item =
|
||||
a_ [href_ hackageLink] (toHtml (item^.name))
|
||||
_otherwise -> toHtml (item^.name)
|
||||
|
||||
renderProCon :: Editable -> UID -> ProCon -> HtmlT IO ()
|
||||
renderProCon Normal _ thing = li_ (toHtml (thing^.proConText))
|
||||
renderProCon Editable itemId' thing = li_ $ do
|
||||
this <- thisNode
|
||||
toHtml (thing^.proConText)
|
||||
textButton "edit" $
|
||||
js_startProConEdit (this, itemId', thing^.proConId)
|
||||
renderProCon InEdit itemId' thing = li_ $ do
|
||||
this <- thisNode
|
||||
let handler = js_submitProConEdit
|
||||
(this, itemId', thing^.proConId, js_this_value)
|
||||
input_ [type_ "text", value_ (thing^.proConText), submitFunc handler]
|
||||
textButton "cancel" $
|
||||
js_cancelProConEdit (this, itemId', thing^.proConId)
|
||||
|
||||
-- Utils
|
||||
|
||||
includeJS :: Monad m => Text -> HtmlT m ()
|
||||
@ -333,7 +386,8 @@ allJSFunctions = [
|
||||
js_addLibrary, js_addCategory,
|
||||
js_startCategoryHeadingEdit, js_submitCategoryHeadingEdit, js_cancelCategoryHeadingEdit,
|
||||
js_addPros, js_addCons,
|
||||
js_enableItemEdit, js_disableItemEdit ]
|
||||
js_enableItemEdit, js_disableItemEdit,
|
||||
js_startProConEdit, js_submitProConEdit, js_cancelProConEdit ]
|
||||
|
||||
-- | Create a new category.
|
||||
js_addCategory :: JSFunction a => a
|
||||
@ -448,6 +502,36 @@ js_disableItemEdit = makeJSFunction "disableItemEdit" [text|
|
||||
}
|
||||
|]
|
||||
|
||||
js_startProConEdit :: JSFunction a => a
|
||||
js_startProConEdit = makeJSFunction "startProConEdit" [text|
|
||||
function startProConEdit(node, itemId, thingId) {
|
||||
$.get("/item/"+itemId+"/pro-con/"+thingId+"/render-edit")
|
||||
.done(function(data) {
|
||||
$(node).replaceWith(data);
|
||||
});
|
||||
}
|
||||
|]
|
||||
|
||||
js_cancelProConEdit :: JSFunction a => a
|
||||
js_cancelProConEdit = makeJSFunction "cancelProConEdit" [text|
|
||||
function cancelProConEdit(node, itemId, thingId) {
|
||||
$.get("/item/"+itemId+"/pro-con/"+thingId+"/render-normal")
|
||||
.done(function(data) {
|
||||
$(node).replaceWith(data);
|
||||
});
|
||||
}
|
||||
|]
|
||||
|
||||
js_submitProConEdit :: JSFunction a => a
|
||||
js_submitProConEdit = makeJSFunction "submitProConEdit" [text|
|
||||
function submitProConEdit(node, itemId, thingId, s) {
|
||||
$.post("/item/"+itemId+"/pro-con/"+thingId+"/set", {content: s})
|
||||
.done(function(data) {
|
||||
$(node).replaceWith(data);
|
||||
});
|
||||
}
|
||||
|]
|
||||
|
||||
-- When adding a function, don't forget to add it to 'allJSFunctions'!
|
||||
|
||||
type JS = Text
|
||||
@ -481,4 +565,4 @@ format f ps = TL.toStrict (Format.format f ps)
|
||||
tshow :: Show a => a -> Text
|
||||
tshow = T.pack . show
|
||||
|
||||
data Editable = Editable | NonEditable
|
||||
data Editable = Normal | Editable | InEdit
|
||||
|
Loading…
Reference in New Issue
Block a user