summaryrefslogtreecommitdiff
path: root/elm3/ProdEdit
diff options
context:
space:
mode:
Diffstat (limited to 'elm3/ProdEdit')
-rw-r--r--elm3/ProdEdit/General.elm78
-rw-r--r--elm3/ProdEdit/Main.elm158
-rw-r--r--elm3/ProdEdit/Names.elm81
-rw-r--r--elm3/ProdEdit/New.elm12
-rw-r--r--elm3/ProdEdit/Relations.elm80
5 files changed, 409 insertions, 0 deletions
diff --git a/elm3/ProdEdit/General.elm b/elm3/ProdEdit/General.elm
new file mode 100644
index 00000000..19ca79b7
--- /dev/null
+++ b/elm3/ProdEdit/General.elm
@@ -0,0 +1,78 @@
+module ProdEdit.General exposing (..)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+import Lib.Html exposing (..)
+import Lib.Gen exposing (languages, weburlPattern, producerTypes, ProdEdit)
+import Lib.Util exposing (..)
+
+
+type alias Model =
+ { desc : String
+ , l_wp : String
+ , lang : String
+ , ptype : String
+ , website : String
+ }
+
+
+init : ProdEdit -> Model
+init d =
+ { desc = d.desc
+ , l_wp = d.l_wp
+ , lang = d.lang
+ , ptype = d.ptype
+ , website = d.website
+ }
+
+
+new : Model
+new =
+ { desc = ""
+ , l_wp = ""
+ , lang = "ja"
+ , ptype = "co"
+ , website = ""
+ }
+
+
+type Msg
+ = Desc String
+ | LWP String
+ | Lang String
+ | PType String
+ | Website String
+
+
+update : Msg -> Model -> Model
+update msg model =
+ case msg of
+ Desc s -> { model | desc = s }
+ LWP s -> { model | l_wp = s }
+ Lang s -> { model | lang = s }
+ PType s -> { model | ptype = s }
+ Website s -> { model | website = s }
+
+
+view : Model -> (Msg -> a) -> List (Html a) -> Html a
+view model wrap names = card "general" "General info" [] <|
+ names ++ List.map (Html.map wrap)
+ [ cardRow "Meta" Nothing <| formGroups
+ [ [ label [for "ptype"] [ text "Type" ]
+ , inputSelect [id "ptype", name "ptype", onInput PType] model.ptype producerTypes
+ ]
+ , [ label [for "lang"] [ text "Primary language" ]
+ , inputSelect [id "lang", name "lang", onInput Lang] model.lang languages
+ ]
+ , [ label [for "website"] [ text "Official Website" ]
+ , inputText "website" model.website Website [pattern weburlPattern]
+ ]
+ , [ label [] [ text "Wikipedia" ]
+ , p [] [ text "https://en.wikipedia.org/wiki/", inputText "l_wp" model.l_wp LWP [class "form-control--inline", maxlength 100] ]
+ ]
+ ]
+
+ , cardRow "Description" (Just "English please!") <| formGroup
+ [ inputTextArea "desc" model.desc Desc [rows 8] ]
+ ]
diff --git a/elm3/ProdEdit/Main.elm b/elm3/ProdEdit/Main.elm
new file mode 100644
index 00000000..6d77ba7a
--- /dev/null
+++ b/elm3/ProdEdit/Main.elm
@@ -0,0 +1,158 @@
+module ProdEdit.Main exposing (Model, Msg, main, new, view, update)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Json.Encode as JE
+import Browser
+import Browser.Navigation exposing (load)
+import Lib.Util exposing (splitLn)
+import Lib.Html exposing (..)
+import Lib.Gen exposing (..)
+import Lib.Api as Api
+import Lib.Editsum as Editsum
+import ProdEdit.Names as Names
+import ProdEdit.General as Gen
+import ProdEdit.Relations as Rel
+
+
+main : Program ProdEdit 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
+ , new : Bool
+ , editsum : Editsum.Model
+ , names : Names.Model
+ , general : Gen.Model
+ , relations : Rel.Model
+ , id : Maybe Int
+ , dupProds : List Api.Producer
+ }
+
+
+init : ProdEdit -> Model
+init d =
+ { state = Api.Normal
+ , new = False
+ , editsum = { authmod = d.authmod, editsum = d.editsum, locked = d.locked, hidden = d.hidden }
+ , names = Names.init d
+ , general = Gen.init d
+ , relations = Rel.init d.relations
+ , id = d.id
+ , dupProds = []
+ }
+
+
+new : Model
+new =
+ { state = Api.Normal
+ , new = True
+ , editsum = Editsum.new
+ , names = Names.new
+ , general = Gen.new
+ , relations = Rel.init []
+ , id = Nothing
+ , dupProds = []
+ }
+
+
+encode : Model -> ProdEditSend
+encode model =
+ { editsum = model.editsum.editsum
+ , hidden = model.editsum.hidden
+ , locked = model.editsum.locked
+ , name = model.names.name
+ , original = model.names.original
+ , alias = model.names.alias
+ , desc = model.general.desc
+ , lang = model.general.lang
+ , ptype = model.general.ptype
+ , l_wp = model.general.l_wp
+ , website = model.general.website
+ , relations = List.map (\e -> { pid = e.pid, relation = e.relation }) model.relations.relations
+ }
+
+
+type Msg
+ = Editsum Editsum.Msg
+ | Submit
+ | Submitted Api.Response
+ | Names Names.Msg
+ | General Gen.Msg
+ | Relations Rel.Msg
+ | CheckDup
+ | RecvDup Api.Response
+
+
+update : Msg -> Model -> (Model, Cmd Msg)
+update msg model =
+ case msg of
+ Names m -> ({ model | names = Names.update m model.names, dupProds = [] }, Cmd.none)
+ General m -> ({ model | general = Gen.update m model.general }, Cmd.none)
+ Editsum m -> ({ model | editsum = Editsum.update m model.editsum }, Cmd.none)
+ Relations m -> let (nm, c) = Rel.update m model.relations in ({ model | relations = nm }, Cmd.map Relations c)
+
+ Submit ->
+ let
+ path =
+ case model.id of
+ Just id -> "/p" ++ String.fromInt id ++ "/edit"
+ Nothing -> "/p/add"
+ body = prodeditSendEncode (encode model)
+ in ({ model | state = Api.Loading }, Api.post path body Submitted)
+
+ Submitted (Api.Changed id rev) -> (model, load <| "/p" ++ String.fromInt id ++ "." ++ String.fromInt rev)
+ Submitted r -> ({ model | state = Api.Error r }, Cmd.none)
+
+ CheckDup ->
+ let body = JE.object
+ [ ("search", JE.list JE.string <| List.filter ((/=)"") <| model.names.name :: model.names.original :: model.names.aliasList)
+ , ("hidden", JE.bool True) ]
+ in
+ if List.isEmpty model.dupProds
+ then ({ model | state = Api.Loading }, Api.post "/js/producer.json" body RecvDup)
+ else ({ model | new = False }, Cmd.none)
+
+ RecvDup (Api.ProducerResult dup) ->
+ ({ model | state = Api.Normal, dupProds = dup, new = not (List.isEmpty dup) }, Cmd.none)
+ RecvDup r -> ({ model | state = Api.Error r }, Cmd.none)
+
+
+
+isValid : Model -> Bool
+isValid model = not
+ ( model.names.aliasDuplicates
+ || model.relations.duplicates
+ )
+
+
+view : Model -> Html Msg
+view model =
+ if model.new
+ then form_ CheckDup (model.state == Api.Loading)
+ [ card "new" "Add a new producer" []
+ <| List.map (Html.map Names) <| Names.view model.names
+ , if List.isEmpty model.dupProds
+ then text ""
+ else card "dup" "Possible duplicates" [ div [ class "card__subheading" ] [ text "Please check the list below for possible duplicates." ] ]
+ [ cardRow "" Nothing <| formGroup [ div [ class "form-group__help" ] [
+ ul [] <| List.map (\e ->
+ li [] [ a [ href <| "/p" ++ String.fromInt e.id, title e.original, target "_black" ] [ text e.name ]
+ , text <| if e.hidden then " (deleted)" else "" ]
+ ) model.dupProds
+ ] ] ]
+ , submitButton "Continue" model.state (isValid model) False
+ ]
+
+ else form_ Submit (model.state == Api.Loading)
+ [ Gen.view model.general General <| List.map (Html.map Names) <| Names.view model.names
+ , Html.map Relations <| Rel.view model.relations
+ , Html.map Editsum <| Editsum.view model.editsum
+ , submitButton "Submit" model.state (isValid model) False
+ ]
diff --git a/elm3/ProdEdit/Names.elm b/elm3/ProdEdit/Names.elm
new file mode 100644
index 00000000..e28f4916
--- /dev/null
+++ b/elm3/ProdEdit/Names.elm
@@ -0,0 +1,81 @@
+module ProdEdit.Names exposing (..)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Dict
+import Lib.Html exposing (..)
+import Lib.Gen exposing (ProdEdit)
+import Lib.Util exposing (..)
+
+
+type alias Model =
+ { name : String
+ , original : String
+ , alias : String
+ , aliasList : List String
+ , aliasDuplicates : Bool
+ }
+
+
+init : ProdEdit -> Model
+init d =
+ { name = d.name
+ , original = d.original
+ , alias = d.alias
+ , aliasList = splitLn d.alias
+ , aliasDuplicates = False
+ }
+
+
+new : Model
+new =
+ { name = ""
+ , original = ""
+ , alias = ""
+ , aliasList = []
+ , aliasDuplicates = False
+ }
+
+
+type Msg
+ = Name String
+ | Original String
+ | Alias String
+
+
+update : Msg -> Model -> Model
+update msg model =
+ case msg of
+ Name s -> { model | name = s }
+ Original s -> { model | original = s }
+ Alias s ->
+ { model
+ | alias = s
+ , aliasList = splitLn s
+ , aliasDuplicates = hasDuplicates (model.name :: model.original :: splitLn s)
+ }
+
+
+view : Model -> List (Html Msg)
+view model =
+ [ cardRow "Name" Nothing <| formGroups
+ [ [ label [for "name"] [text "Name (romaji)"]
+ , inputText "name" model.name Name [required True, maxlength 200]
+ ]
+ , [ label [for "original"] [text "Original"]
+ , inputText "original" model.original Original [maxlength 200]
+ , div [class "form-group__help"] [text "The original name of this producer, leave blank if it already is in the Latin alphabet."]
+ ]
+ ]
+ , cardRow "Aliases" Nothing <| formGroup
+ [ inputTextArea "aliases" model.alias Alias
+ [ rows 4, maxlength 500
+ , classList [("is-invalid", model.aliasDuplicates)]
+ ]
+ , if model.aliasDuplicates
+ then div [class "invalid-feedback"]
+ [ text "There are duplicate aliases." ]
+ else text ""
+ , div [class "form-group__help"] [ text "(Un)official aliases, separated by a newline." ]
+ ]
+ ]
diff --git a/elm3/ProdEdit/New.elm b/elm3/ProdEdit/New.elm
new file mode 100644
index 00000000..c1df2ac4
--- /dev/null
+++ b/elm3/ProdEdit/New.elm
@@ -0,0 +1,12 @@
+module ProdEdit.New exposing (main)
+
+import Browser
+import ProdEdit.Main as Main
+
+main : Program () Main.Model Main.Msg
+main = Browser.element
+ { init = always (Main.new, Cmd.none)
+ , view = Main.view
+ , update = Main.update
+ , subscriptions = always Sub.none
+ }
diff --git a/elm3/ProdEdit/Relations.elm b/elm3/ProdEdit/Relations.elm
new file mode 100644
index 00000000..a74339f1
--- /dev/null
+++ b/elm3/ProdEdit/Relations.elm
@@ -0,0 +1,80 @@
+module ProdEdit.Relations exposing (Model, Msg, init, update, view)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+import Lib.Html exposing (..)
+import Lib.Gen exposing (ProdEditRelations, producerRelations)
+import Lib.Api exposing (Producer)
+import Lib.Util exposing (..)
+import Lib.Autocomplete as A
+
+
+type alias Model =
+ { relations : List ProdEditRelations
+ , search : A.Model Producer
+ , duplicates : Bool
+ }
+
+
+init : List ProdEditRelations -> Model
+init l =
+ { relations = l
+ , search = A.init
+ , duplicates = False
+ }
+
+
+type Msg
+ = Del Int
+ | Rel Int String
+ | Search (A.Msg Producer)
+
+
+searchConfig : A.Config Msg Producer
+searchConfig = { wrap = Search, id = "add-relation", source = A.producerSource }
+
+
+validate : Model -> Model
+validate model = { model | duplicates = hasDuplicates <| List.map .pid model.relations }
+
+
+update : Msg -> Model -> (Model, Cmd Msg)
+update msg model =
+ case msg of
+ Del i -> (validate { model | relations = delidx i model.relations }, Cmd.none)
+ Rel i s -> (validate { model | relations = modidx i (\e -> { e | relation = s }) model.relations }, Cmd.none)
+ Search m ->
+ let (nm, c, res) = A.update searchConfig m model.search
+ in case res of
+ Nothing -> ({ model | search = nm }, c)
+ Just r ->
+ let
+ rel = List.head producerRelations |> Maybe.map Tuple.first |> Maybe.withDefault ""
+ nrow = { pid = r.id, relation = rel, name = r.name }
+ in (validate { model | search = A.clear nm, relations = model.relations ++ [nrow] }, c)
+
+
+view : Model -> Html Msg
+view model =
+ let
+ entry n e = editListRow "row--ai-center"
+ [ editListField 1 "single-line"
+ [ a [href <| "/p" ++ String.fromInt e.pid, title e.name, target "_blank" ] [text e.name ] ]
+ , editListField 1 ""
+ [ inputSelect [onInput (Rel n)] e.relation producerRelations ]
+ , editListField 0 "" [ removeButton (Del n) ]
+ ]
+
+ in card "relations" "Relations" [] <|
+ editList (List.indexedMap entry model.relations)
+ ++ formGroups (
+ (if model.duplicates
+ then [ [ div [ class "invalid-feedback" ]
+ [ text "The list contains duplicates. Make sure that the same producer is not listed multiple times." ] ] ]
+ else []
+ ) ++
+ [ label [for "add-relation"] [text "Add relation"]
+ :: A.view searchConfig model.search [placeholder "Producer...", style "max-width" "400px"]
+ ]
+ )