1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
module UVNList.Vote exposing (main)
-- XXX: There's some unobvious and unintuitive behavior when removing a vote:
-- If the VN isn't also in the user's 'vnlist', then the VN entry will be
-- removed from the user's list and this is only visible on a page refresh. A
-- clean solution to this is to merge the 'votes' and 'vnlist' tables so that
-- there's always a 'vnlist' entry that remains. This is best done after VNDBv2
-- has been decommissioned.
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Json.Encode as JE
import Browser
import Regex
import Lib.Api as Api
import Lib.Gen exposing (vnvotePattern)
main : Program Flags Model Msg
main = Browser.element
{ init = \f -> (init f, Cmd.none)
, subscriptions = always Sub.none
, view = view
, update = update
}
type alias Flags =
{ uid : Int
, vid : Int
, vote : String
}
type alias Model =
{ state : Api.State
, flags : Flags
, text : String
, valid : Bool
}
init : Flags -> Model
init f =
{ state = Api.Normal
, flags = f
, text = f.vote
, valid = True
}
encodeForm : Model -> JE.Value
encodeForm o = JE.object
[ ("uid", JE.int o.flags.uid)
, ("vid", JE.int o.flags.vid)
, ("vote", JE.string o.text) ]
type Msg
= Input String
| Save
| Saved Api.Response
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Input s ->
( { model | text = s
, valid = Regex.contains (Maybe.withDefault Regex.never <| Regex.fromString vnvotePattern) s
}
, Cmd.none
)
Save ->
if model.valid && model.text /= model.flags.vote
then ( { model | state = Api.Loading }
, Api.post "/u/setvote" (encodeForm model) Saved )
else (model, Cmd.none)
Saved Api.Success ->
let flags = model.flags
nflags = { flags | vote = model.text }
in ({ model | flags = nflags, state = Api.Normal }, Cmd.none)
Saved e -> ({ model | state = Api.Error e }, Cmd.none)
view : Model -> Html Msg
view model =
-- TODO: Display error somewhere
-- TODO: Save when pressing enter
if model.state == Api.Loading
then
div [ class "spinner spinner--md" ] []
else
input
[ type_ "text"
, pattern vnvotePattern
, class "form-control form-control--table-edit form-control--stealth"
, classList [("is-invalid", not model.valid)]
, value model.text
, onInput Input
, onBlur Save
] []
|