summaryrefslogtreecommitdiff
path: root/elm/UList/LabelEdit.elm
blob: 471f6eb64bedf8a7b145fc4f6399de5416ff8cce (plain)
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
port module UList.LabelEdit exposing (main, init, update, view, isPublic, Model, Msg)

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Browser
import Set exposing (Set)
import Dict exposing (Dict)
import Lib.Html exposing (..)
import Lib.Api as Api
import Lib.DropDown as DD
import Gen.Api as GApi
import Gen.UListLabelEdit as GLE


main : Program GLE.Recv Model Msg
main = Browser.element
  { init = \f -> (init f, Cmd.none)
  , subscriptions = \model -> DD.sub model.dd
  , view = view
  , update = update
  }

port ulistLabelChanged : Bool -> Cmd msg

type alias Model =
  { uid      : Int
  , vid      : Int
  , labels   : List GLE.RecvLabels
  , sel      : Set Int -- Set of label IDs applied on the server
  , tsel     : Set Int -- Set of label IDs applied on the client
  , state    : Dict Int Api.State -- Only for labels that are being changed
  , dd       : DD.Config Msg
  }

init : GLE.Recv -> Model
init f =
  { uid      = f.uid
  , vid      = f.vid
  , labels   = f.labels
  , sel      = Set.fromList f.selected
  , tsel     = Set.fromList f.selected
  , state    = Dict.empty
  , dd       = DD.init ("ulist_labeledit_dd" ++ String.fromInt f.vid) Open
  }

type Msg
  = Open Bool
  | Toggle Int Bool
  | Saved Int Bool GApi.Response


isPublic : Model -> Bool
isPublic model = List.any (\lb -> lb.id /= 7 && not lb.private && Set.member lb.id model.sel) model.labels

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Open b -> ({ model | dd = DD.toggle model.dd b }, Cmd.none)

    Toggle l b ->
      ( { model
        | tsel   = if b then Set.insert l model.tsel else Set.remove l model.tsel
        , state  = Dict.insert l Api.Loading model.state
        }
      , Api.post "/u/ulist/setlabel.json" (GLE.encode { uid = model.uid, vid = model.vid, label = l, applied = b }) (Saved l b)
      )

    Saved l b (GApi.Success) ->
      let nmodel = { model | sel = if b then Set.insert l model.sel else Set.remove l model.sel, state = Dict.remove l model.state }
       in (nmodel, ulistLabelChanged (isPublic nmodel))
    Saved l b e -> ({ model | state = Dict.insert l (Api.Error e) model.state }, Cmd.none)


view : Model -> Html Msg
view model =
  let
    str = String.join ", " <| List.filterMap (\l -> if Set.member l.id model.sel then Just l.label else Nothing) model.labels

    item l =
      li [ ]
      [ linkRadio (Set.member l.id model.tsel) (Toggle l.id)
        [ text l.label
        , text " "
        , span [ class "spinner", classList [("invisible", Dict.get l.id model.state /= Just Api.Loading)] ] []
        , case Dict.get l.id model.state of
            Just (Api.Error _) -> b [ class "standout" ] [ text "error" ] -- Need something better
            _ -> text ""
        ]
      ]
  in
    DD.view model.dd
      (if List.any (\s -> s == Api.Loading) <| Dict.values model.state then Api.Loading else Api.Normal)
      (text <| if str == "" then "-" else str)
      (\_ -> [ ul [] <| List.map item <| List.filter (\l -> l.id /= 7) model.labels ])