summaryrefslogtreecommitdiff
path: root/elm
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2019-12-01 09:22:20 +0100
committerYorhel <git@yorhel.nl>2019-12-01 13:40:59 +0100
commit165b62acc991cbf30cb721af27b04a066dbc9413 (patch)
tree34cbe7fef4a020fe121ddf1026dd6be13e9498a2 /elm
parentb2ba46a9a0900d2b9d62a5ff84c4d4c9d9780abc (diff)
v2rw: Convert thread display + poll voting
I did not reimplement the 'poll_recast' and 'poll_preview' settings, these actions are now always permitted. Updated CSS a little bit to highlight the linked post and fix the double border at the bottom. The nice thing about the sql_visible_threads() function I wrote earlier is that is can also be used for access control on a single thread. More code re-use. \o/
Diffstat (limited to 'elm')
-rw-r--r--elm/Discussions/Poll.elm139
-rw-r--r--elm/DocEdit.elm2
-rw-r--r--elm/Lib/Html.elm8
-rw-r--r--elm/StaffEdit/Main.elm2
-rw-r--r--elm/UList/ManageLabels.elm2
-rw-r--r--elm/User/Edit.elm2
-rw-r--r--elm/User/Login.elm2
-rw-r--r--elm/User/PassReset.elm2
-rw-r--r--elm/User/PassSet.elm2
-rw-r--r--elm/User/Register.elm2
10 files changed, 151 insertions, 12 deletions
diff --git a/elm/Discussions/Poll.elm b/elm/Discussions/Poll.elm
new file mode 100644
index 00000000..40037ba8
--- /dev/null
+++ b/elm/Discussions/Poll.elm
@@ -0,0 +1,139 @@
+module Discussions.Poll exposing (main)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+import Browser
+import Lib.Html exposing (..)
+import Lib.TextPreview as TP
+import Lib.Api as Api
+import Gen.Api as GApi
+import Gen.DiscussionsPoll as GDP
+
+
+main : Program GDP.Recv Model Msg
+main = Browser.element
+ { init = \e -> (init e, Cmd.none)
+ , view = view
+ , update = update
+ , subscriptions = always Sub.none
+ }
+
+
+type alias Model =
+ { state : Api.State
+ , data : GDP.Recv
+ , voted : Bool
+ }
+
+
+init : GDP.Recv -> Model
+init d =
+ { state = Api.Normal
+ -- Remove own vote from the count, so we can dynamically adjust the counter
+ , data = { d | options = List.map (\o -> { o | votes = if o.my then o.votes - 1 else o.votes }) d.options }
+ , voted = List.any (\o -> o.my) d.options
+ }
+
+type Msg
+ = Preview
+ | Vote Int Bool
+ | Submit
+ | Submitted GApi.Response
+
+
+toomany : Model -> Bool
+toomany model = List.length (List.filter (\o -> o.my) model.data.options) > model.data.max_options
+
+update : Msg -> Model -> (Model, Cmd Msg)
+update msg model =
+ case msg of
+ Preview ->
+ let d = model.data
+ nd = { d | preview = True }
+ in ({ model | data = nd }, Cmd.none)
+
+ Vote n b ->
+ let d = model.data
+ nd = { d | options = List.map (\o -> { o | my = if n == o.id then b else o.my && d.max_options > 1 }) d.options }
+ in ({ model | data = nd }, Cmd.none)
+
+ Submit ->
+ if toomany model then (model, Cmd.none)
+ else
+ ( { model | state = Api.Loading }
+ , Api.post "/t/pollvote.json" (GDP.encode { tid = model.data.tid, options = List.filterMap (\o -> if o.my then Just o.id else Nothing) model.data.options }) Submitted
+ )
+
+ Submitted (GApi.Success) ->
+ let d = model.data
+ v = List.any (\o -> o.my) model.data.options
+ nd = { d | num_votes = model.data.num_votes +
+ case (model.voted, v) of
+ (True, False) -> -1
+ (False, True) -> 1
+ _ -> 0 }
+ in ({ model | state = Api.Normal, voted = v, data = nd }, Cmd.none)
+ Submitted r -> ({ model | state = Api.Error r }, Cmd.none)
+
+
+view : Model -> Html Msg
+view model =
+ let
+ cvotes = model.data.num_votes + (if not model.voted && List.any (\o -> o.my) model.data.options then 1 else 0)
+ nvotes o = if o.my then o.votes + 1 else o.votes
+ max = toFloat <| Maybe.withDefault 1 <| List.maximum <| List.map nvotes model.data.options
+
+ opt o =
+ tr [ classList [("odd", o.my)] ]
+ [ td [ class "tc1" ]
+ [ label []
+ [ if not model.data.can_vote
+ then text ""
+ else if model.data.max_options == 1
+ then inputRadio "vote" o.my (Vote o.id)
+ else inputCheck "" o.my (Vote o.id)
+ , span [ class "option", classList [("own", o.my)] ] [ text o.option ]
+ ]
+ ]
+ , if model.data.preview || model.voted
+ then td [ class "tc2" ]
+ [ div [ class "graph", style "width" (String.fromFloat (toFloat (nvotes o) / max * 200) ++ "px") ] [ text " " ]
+ , div [ class "number" ] [ text <| String.fromInt (nvotes o) ]
+ ]
+ else td [ class "tc2", colspan 2 ] []
+ , if model.data.preview || model.voted
+ then td [ class "tc3" ]
+ [ let pc = toFloat (nvotes o) / toFloat cvotes * 100
+ in text <| String.fromInt (truncate pc) ++ "%" ]
+ else text ""
+ ]
+ in
+ form_ Submit (model.state == Api.Loading)
+ [ div [ class "mainbox" ]
+ [ h1 [] [ text model.data.question ]
+ , table [ class "votebooth" ]
+ [ if model.data.can_vote && model.data.max_options > 1
+ then thead [] [ tr [] [ td [ colspan 3 ] [ i [] [ text <| "You may choose up to " ++ String.fromInt model.data.max_options ++ " options" ] ] ] ]
+ else text ""
+ , tfoot [] [ tr []
+ [ td [ class "tc1" ]
+ [ if model.data.can_vote
+ then submitButton "Vote" model.state True
+ else b [ class "standout" ] [ text "You must be logged in to be able to vote." ]
+ , if toomany model
+ then b [ class "standout" ] [ text "Too many options selected." ]
+ else text ""
+ ]
+ , td [ class "tc2" ]
+ [ if model.data.num_votes == 0
+ then i [] [ text "Nobody voted yet" ]
+ else if model.data.preview || model.voted
+ then text <| (String.fromInt model.data.num_votes) ++ (if model.data.num_votes == 1 then " vote total" else " votes total")
+ else a [ href "#", onClickD Preview ] [ text "View results" ]
+ ]
+ ] ]
+ , tbody [] <| List.map opt model.data.options
+ ]
+ ]
+ ]
diff --git a/elm/DocEdit.elm b/elm/DocEdit.elm
index ef4ce715..b9d70622 100644
--- a/elm/DocEdit.elm
+++ b/elm/DocEdit.elm
@@ -101,7 +101,7 @@ view model =
, div [ class "mainbox" ]
[ fieldset [ class "submit" ]
[ Html.map Editsum (Editsum.view model.editsum)
- , submitButton "Submit" model.state True False
+ , submitButton "Submit" model.state True
]
]
]
diff --git a/elm/Lib/Html.elm b/elm/Lib/Html.elm
index d75dced4..1e995f86 100644
--- a/elm/Lib/Html.elm
+++ b/elm/Lib/Html.elm
@@ -45,15 +45,15 @@ inputButton val onch attrs =
-- Submit button with loading indicator and error message display
-submitButton : String -> Api.State -> Bool -> Bool -> Html m
-submitButton val state valid load = div []
- [ input [ type_ "submit", class "submit", tabindex 10, value val, disabled (state == Api.Loading || not valid || load) ] []
+submitButton : String -> Api.State -> Bool -> Html m
+submitButton val state valid = div []
+ [ input [ type_ "submit", class "submit", tabindex 10, value val, disabled (state == Api.Loading || not valid) ] []
, case state of
Api.Error r -> p [] [ b [class "standout" ] [ text <| Api.showResponse r ] ]
_ -> if valid
then text ""
else p [] [ b [class "standout" ] [ text "The form contains errors, please fix these before submitting. " ] ]
- , if state == Api.Loading || load
+ , if state == Api.Loading
then div [ class "spinner" ] []
else text ""
]
diff --git a/elm/StaffEdit/Main.elm b/elm/StaffEdit/Main.elm
index 9765f0c0..b7bef54a 100644
--- a/elm/StaffEdit/Main.elm
+++ b/elm/StaffEdit/Main.elm
@@ -222,7 +222,7 @@ view model =
, div [ class "mainbox" ]
[ fieldset [ class "submit" ]
[ Html.map Editsum (Editsum.view model.editsum)
- , submitButton "Submit" model.state (isValid model) False
+ , submitButton "Submit" model.state (isValid model)
]
]
]
diff --git a/elm/UList/ManageLabels.elm b/elm/UList/ManageLabels.elm
index 7f951389..c3e996f8 100644
--- a/elm/UList/ManageLabels.elm
+++ b/elm/UList/ManageLabels.elm
@@ -111,7 +111,7 @@ view model =
, td [ colspan 3 ]
[ a [ onClick Add ] [ text "New label" ]
--, inputButton "Save changes" Noop []
- , submitButton "Save changes" model.state True False
+ , submitButton "Save changes" model.state True
]
] ]
, tbody [] <| List.indexedMap item model.labels
diff --git a/elm/User/Edit.elm b/elm/User/Edit.elm
index 1a13cdb1..1a9b9a55 100644
--- a/elm/User/Edit.elm
+++ b/elm/User/Edit.elm
@@ -217,7 +217,7 @@ view model =
]
, div [ class "mainbox" ]
- [ fieldset [ class "submit" ] [ submitButton "Submit" model.state (not model.passNeq) False ]
+ [ fieldset [ class "submit" ] [ submitButton "Submit" model.state (not model.passNeq) ]
, if not model.mailConfirm then text "" else
div [ class "notice" ]
[ text "A confirmation email has been sent to your new address. Your address will be updated after following the instructions in that mail." ]
diff --git a/elm/User/Login.elm b/elm/User/Login.elm
index bef69cb5..cc25d132 100644
--- a/elm/User/Login.elm
+++ b/elm/User/Login.elm
@@ -144,6 +144,6 @@ view model =
in form_ Submit (model.state == Api.Loading)
[ if model.insecure then changeBox else loginBox
, div [ class "mainbox" ]
- [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True False ]
+ [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True ]
]
]
diff --git a/elm/User/PassReset.elm b/elm/User/PassReset.elm
index ad265c87..c1b5b516 100644
--- a/elm/User/PassReset.elm
+++ b/elm/User/PassReset.elm
@@ -81,6 +81,6 @@ view model =
]
]
, div [ class "mainbox" ]
- [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True False ]
+ [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True ]
]
]
diff --git a/elm/User/PassSet.elm b/elm/User/PassSet.elm
index 3c5c50bc..bc5cc24d 100644
--- a/elm/User/PassSet.elm
+++ b/elm/User/PassSet.elm
@@ -84,6 +84,6 @@ view model =
]
]
, div [ class "mainbox" ]
- [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True False ]
+ [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True ]
]
]
diff --git a/elm/User/Register.elm b/elm/User/Register.elm
index d4749e47..add16418 100644
--- a/elm/User/Register.elm
+++ b/elm/User/Register.elm
@@ -100,6 +100,6 @@ view model =
]
]
, div [ class "mainbox" ]
- [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True False ]
+ [ fieldset [ class "submit" ] [ submitButton "Submit" model.state True ]
]
]