summaryrefslogtreecommitdiff
path: root/elm/ReleaseEdit.elm
diff options
context:
space:
mode:
Diffstat (limited to 'elm/ReleaseEdit.elm')
-rw-r--r--elm/ReleaseEdit.elm450
1 files changed, 0 insertions, 450 deletions
diff --git a/elm/ReleaseEdit.elm b/elm/ReleaseEdit.elm
deleted file mode 100644
index 1bcf91c5..00000000
--- a/elm/ReleaseEdit.elm
+++ /dev/null
@@ -1,450 +0,0 @@
-module ReleaseEdit exposing (main)
-
-import Html exposing (..)
-import Html.Events exposing (..)
-import Html.Attributes exposing (..)
-import Browser
-import Browser.Navigation exposing (load)
-import Set
-import Lib.Util exposing (..)
-import Lib.Html exposing (..)
-import Lib.TextPreview as TP
-import Lib.Api as Api
-import Lib.DropDown as DD
-import Lib.Editsum as Editsum
-import Lib.RDate as D
-import Lib.Autocomplete as A
-import Lib.ExtLinks as EL
-import Gen.ReleaseEdit as GRE
-import Gen.Types as GT
-import Gen.Api as GApi
-import Gen.ExtLinks as GEL
-
-
-main : Program GRE.Recv Model Msg
-main = Browser.element
- { init = \e -> (init e, Cmd.none)
- , view = view
- , update = update
- , subscriptions = sub
- }
-
-
-type alias Model =
- { state : Api.State
- , title : String
- , original : String
- , rtype : String
- , patch : Bool
- , freeware : Bool
- , doujin : Bool
- , lang : Set.Set String
- , langDd : DD.Config Msg
- , plat : Set.Set String
- , platDd : DD.Config Msg
- , media : List GRE.RecvMedia
- , gtin : String
- , gtinValid : Bool
- , catalog : String
- , released : D.RDate
- , minage : Int
- , uncensored : Bool
- , resoX : Int
- , resoY : Int
- , resoConf : A.Config Msg GRE.RecvResolutions
- , reso : A.Model GRE.RecvResolutions
- , voiced : Int
- , ani_story : Int
- , ani_ero : Int
- , website : String
- , engineConf : A.Config Msg GRE.RecvEngines
- , engine : A.Model GRE.RecvEngines
- , extlinks : EL.Model GRE.RecvExtlinks
- , vn : List GRE.RecvVn
- , vnAdd : A.Model GApi.ApiVNResult
- , prod : List GRE.RecvProducers
- , prodAdd : A.Model GApi.ApiProducerResult
- , notes : TP.Model
- , editsum : Editsum.Model
- , id : Maybe Int
- }
-
-
-engineConf : List GRE.RecvEngines -> A.Config Msg GRE.RecvEngines
-engineConf lst =
- { wrap = Engine
- , id = "engine"
- , source =
- { source = A.Func (\s -> List.filter (\e -> String.contains (String.toLower s) (String.toLower e.engine)) lst |> List.take 10)
- , view = \i -> [ text i.engine, b [ class "grayedout" ] [ text <| " (" ++ String.fromInt i.count ++ ")" ] ]
- , key = \i -> i.engine
- }
- }
-
-
-resoConf : List GRE.RecvResolutions -> A.Config Msg GRE.RecvResolutions
-resoConf lst =
- { wrap = Resolution
- , id = "resolution"
- , source =
- { source = A.Func (\s -> List.filter (\e -> String.contains (String.toLower s) (String.toLower e.resolution)) lst |> List.take 10)
- , view = \i -> [ text i.resolution, b [ class "grayedout" ] [ text <| " (" ++ String.fromInt i.count ++ ")" ] ]
- , key = \i -> i.resolution
- }
- }
-
-resoFmt : Int -> Int -> String
-resoFmt x y =
- case (x,y) of
- (0,0) -> ""
- (0,1) -> "Non-standard"
- _ -> String.fromInt x ++ "x" ++ String.fromInt y
-
-resoParse : String -> Maybe (Int, Int)
-resoParse s =
- let t = String.replace "*" "x" s
- |> String.replace "×" "x"
- |> String.replace " " ""
- |> String.replace "\t" ""
- |> String.toLower |> String.trim
- in
- case (t, String.split "x" t) of
- ("", _) -> Just (0,0)
- ("non-standard", _) -> Just (0,1)
- (_, [sx,sy]) ->
- case (String.toInt sx, String.toInt sy) of
- (Just ix, Just iy) -> if ix < 1 || ix > 32767 || iy < 1 || iy > 32767 then Nothing else Just (ix,iy)
- _ -> Nothing
- _ -> Nothing
-
-
-init : GRE.Recv -> Model
-init d =
- { state = Api.Normal
- , title = d.title
- , original = d.original
- , rtype = d.rtype
- , patch = d.patch
- , freeware = d.freeware
- , doujin = d.doujin
- , lang = Set.fromList <| List.map (\e -> e.lang) d.lang
- , langDd = DD.init "lang" LangOpen
- , plat = Set.fromList <| List.map (\e -> e.platform) d.platforms
- , platDd = DD.init "platforms" PlatOpen
- , media = List.map (\m -> { m | qty = if m.qty == 0 then 1 else m.qty }) d.media
- , gtin = if d.gtin == "0" then "" else String.padLeft 12 '0' d.gtin
- , gtinValid = True
- , catalog = d.catalog
- , released = d.released
- , minage = d.minage
- , uncensored = d.uncensored
- , resoX = d.reso_x
- , resoY = d.reso_y
- , resoConf = resoConf d.resolutions
- , reso = A.init (resoFmt d.reso_x d.reso_y)
- , voiced = d.voiced
- , ani_story = d.ani_story
- , ani_ero = d.ani_ero
- , website = d.website
- , engineConf = engineConf d.engines
- , engine = A.init d.engine
- , extlinks = EL.new d.extlinks GEL.releaseSites
- , vn = d.vn
- , vnAdd = A.init ""
- , prod = d.producers
- , prodAdd = A.init ""
- , notes = TP.bbcode d.notes
- , editsum = { authmod = d.authmod, editsum = TP.bbcode d.editsum, locked = d.locked, hidden = d.hidden }
- , id = d.id
- }
-
-
-encode : Model -> GRE.Send
-encode model =
- { id = model.id
- , editsum = model.editsum.editsum.data
- , hidden = model.editsum.hidden
- , locked = model.editsum.locked
- , title = model.title
- , original = model.original
- , rtype = model.rtype
- , patch = model.patch
- , freeware = model.freeware
- , doujin = model.doujin
- , lang = List.map (\l -> {lang=l }) <| Set.toList model.lang
- , platforms = List.map (\l -> {platform=l}) <| Set.toList model.plat
- , media = model.media
- , gtin = model.gtin
- , catalog = model.catalog
- , released = model.released
- , minage = model.minage
- , uncensored = model.uncensored
- , reso_x = model.resoX
- , reso_y = model.resoY
- , voiced = model.voiced
- , ani_story = model.ani_story
- , ani_ero = model.ani_ero
- , website = model.website
- , engine = model.engine.value
- , extlinks = model.extlinks.links
- , vn = List.map (\l -> {vid=l.vid}) model.vn
- , producers = List.map (\l -> {pid=l.pid, developer=l.developer, publisher=l.publisher}) model.prod
- , notes = model.notes.data
- }
-
-vnConfig : A.Config Msg GApi.ApiVNResult
-vnConfig = { wrap = VNSearch, id = "vnadd", source = A.vnSource }
-
-producerConfig : A.Config Msg GApi.ApiProducerResult
-producerConfig = { wrap = ProdSearch, id = "prodadd", source = A.producerSource }
-
-sub : Model -> Sub Msg
-sub m = Sub.batch [ DD.sub m.langDd, DD.sub m.platDd ]
-
-type Msg
- = Title String
- | Original String
- | RType String
- | Patch Bool
- | Freeware Bool
- | Doujin Bool
- | Lang String Bool
- | LangOpen Bool
- | Plat String Bool
- | PlatOpen Bool
- | MediaType Int String
- | MediaQty Int Int
- | MediaDel Int
- | Gtin String
- | Catalog String
- | Released D.RDate
- | Minage Int
- | Uncensored Bool
- | Resolution (A.Msg GRE.RecvResolutions)
- | Voiced Int
- | AniStory Int
- | AniEro Int
- | Website String
- | Engine (A.Msg GRE.RecvEngines)
- | ExtLinks (EL.Msg GRE.RecvExtlinks)
- | VNDel Int
- | VNSearch (A.Msg GApi.ApiVNResult)
- | ProdDel Int
- | ProdRole Int (Bool, Bool)
- | ProdSearch (A.Msg GApi.ApiProducerResult)
- | Notes (TP.Msg)
- | Editsum Editsum.Msg
- | Submit
- | Submitted GApi.Response
-
-
-update : Msg -> Model -> (Model, Cmd Msg)
-update msg model =
- case msg of
- Title s -> ({ model | title = s }, Cmd.none)
- Original s -> ({ model | original = s }, Cmd.none)
- RType s -> ({ model | rtype = s }, Cmd.none)
- Patch b -> ({ model | patch = b }, Cmd.none)
- Freeware b -> ({ model | freeware = b }, Cmd.none)
- Doujin b -> ({ model | doujin = b }, Cmd.none)
- Lang s b -> ({ model | lang = if b then Set.insert s model.lang else Set.remove s model.lang }, Cmd.none)
- LangOpen b -> ({ model | langDd = DD.toggle model.langDd b }, Cmd.none)
- Plat s b -> ({ model | plat = if b then Set.insert s model.plat else Set.remove s model.plat }, Cmd.none)
- PlatOpen b -> ({ model | platDd = DD.toggle model.platDd b }, Cmd.none)
- MediaType n s -> ({ model | media = if s /= "unk" && n == List.length model.media then model.media ++ [{medium = s, qty = 1}] else modidx n (\m -> { m | medium = s }) model.media }, Cmd.none)
- MediaQty n i -> ({ model | media = modidx n (\m -> { m | qty = i }) model.media }, Cmd.none)
- MediaDel i -> ({ model | media = delidx i model.media }, Cmd.none)
- Gtin s -> ({ model | gtin = s, gtinValid = s == "" || validateGtin s }, Cmd.none)
- Catalog s -> ({ model | catalog = s }, Cmd.none)
- Released d -> ({ model | released = d }, Cmd.none)
- Minage i -> ({ model | minage = i }, Cmd.none)
- Uncensored b->({ model | uncensored = b }, Cmd.none)
- Resolution m->
- let (nm, c, en) = A.update model.resoConf m model.reso
- nmod = { model | reso = Maybe.withDefault nm <| Maybe.map (\e -> A.clear nm e.resolution) en }
- n2mod = case resoParse nmod.reso.value of
- Just (x,y) -> { nmod | resoX = x, resoY = y }
- Nothing -> nmod
- in (n2mod, c)
- Voiced i -> ({ model | voiced = i }, Cmd.none)
- AniStory i -> ({ model | ani_story = i }, Cmd.none)
- AniEro i -> ({ model | ani_ero = i }, Cmd.none)
- Website s -> ({ model | website = s }, Cmd.none)
- Engine m ->
- let (nm, c, en) = A.update model.engineConf m model.engine
- nmod = case en of
- Just e -> A.clear nm e.engine
- Nothing -> nm
- in ({ model | engine = nmod }, c)
- ExtLinks m -> ({ model | extlinks = EL.update m model.extlinks }, Cmd.none)
-
- VNDel i -> ({ model | vn = delidx i model.vn }, Cmd.none)
- VNSearch m ->
- let (nm, c, res) = A.update vnConfig m model.vnAdd
- in case res of
- Nothing -> ({ model | vnAdd = nm }, c)
- Just v ->
- if List.any (\vn -> vn.vid == v.id) model.vn
- then ({ model | vnAdd = nm }, c)
- else ({ model | vnAdd = A.clear nm "", vn = model.vn ++ [{ vid = v.id, title = v.title}] }, c)
-
- ProdDel i -> ({ model | prod = delidx i model.prod }, Cmd.none)
- ProdRole i (d,p) -> ({ model | prod = modidx i (\e -> { e | developer = d, publisher = p }) model.prod }, Cmd.none)
- ProdSearch m ->
- let (nm, c, res) = A.update producerConfig m model.prodAdd
- in case res of
- Nothing -> ({ model | prodAdd = nm }, c)
- Just p ->
- if List.any (\e -> e.pid == p.id) model.prod
- then ({ model | prodAdd = nm }, c)
- else ({ model | prodAdd = A.clear nm "", prod = model.prod ++ [{ pid = p.id, name = p.name, developer = True, publisher = True}] }, c)
-
- Notes m -> let (nm, nc) = TP.update m model.notes in ({ model | notes = nm }, Cmd.map Notes nc)
- Editsum m -> let (nm,nc) = Editsum.update m model.editsum in ({ model | editsum = nm }, Cmd.map Editsum nc)
-
- Submit -> ({ model | state = Api.Loading }, GRE.send (encode model) Submitted)
- Submitted (GApi.Redirect s) -> (model, load s)
- Submitted r -> ({ model | state = Api.Error r }, Cmd.none)
-
-
-isValid : Model -> Bool
-isValid model = not
- ( model.title == model.original
- || Set.isEmpty model.lang
- || hasDuplicates (List.map (\m -> (m.medium, m.qty)) model.media)
- || not model.gtinValid
- || List.isEmpty model.vn
- || resoParse model.reso.value == Nothing
- )
-
-
-viewGen : Model -> Html Msg
-viewGen model =
- table [ class "formtable" ]
- [ formField "title::Title (romaji)"
- [ inputText "title" model.title Title (style "width" "500px" :: GRE.valTitle)
- , if containsNonLatin model.title
- then b [ class "standout" ] [ br [] [], text "This title field should only contain latin-alphabet characters, please put the \"actual\" title in the field below and the romanization above." ]
- else text ""
- ]
- , formField "original::Original title"
- [ inputText "original" model.original Original (style "width" "500px" :: GRE.valOriginal)
- , if model.title /= "" && model.title == model.original
- then b [ class "standout" ] [ br [] [], text "Should not be the same as the Title (romaji). Leave blank is the original title is already in the latin alphabet" ]
- else if model.original /= "" && not (containsNonLatin model.original)
- then b [ class "standout" ] [ br [] [], text "Original title does not seem to contain any non-latin characters. Leave this field empty if the title is already in the latin alphabet" ]
- else if containsJapanese model.original && not (Set.isEmpty model.lang) && not (Set.member "ja" model.lang)
- then b [ class "standout" ] [ br [] [], text "Non-Japanese releases should (probably) not have a Japanese original title." ]
- else text ""
- ]
-
- , tr [ class "newpart" ] [ td [] [] ]
- , formField "rtype::Type" [ inputSelect "rtype" model.rtype RType [] GT.releaseTypes ]
- , formField "minage::Age rating" [ inputSelect "minage" model.minage Minage [] GT.ageRatings, text " (*)" ]
- , formField "" [ label [] [ inputCheck "" model.patch Patch , text " This release is a patch to another release.", text " (*)" ] ]
- , formField "" [ label [] [ inputCheck "" model.freeware Freeware, text " Freeware (i.e. available at no cost)" ] ]
- , if model.patch then text "" else
- formField "" [ label [] [ inputCheck "" model.doujin Doujin , text " Doujin (self-published, not by a company)" ] ]
- , formField "Release date" [ D.view model.released False Released, text " Leave month or day blank if they are unknown." ]
-
- , tr [ class "newpart" ] [ td [ colspan 2 ] [ text "Format" ] ]
- , formField "Language(s)"
- [ div [ class "elm_dd_input", style "width" "500px" ] [ DD.view model.langDd Api.Normal
- (if Set.isEmpty model.lang
- then b [ class "standout" ] [ text "No language selected" ]
- else span [] <| List.intersperse (text ", ") <| List.map (\(l,t) -> span [ style "white-space" "nowrap" ] [ langIcon l, text t ]) <| List.filter (\(l,_) -> Set.member l model.lang) GT.languages)
- <| \() -> [ ul [ style "columns" "2"] <| List.map (\(l,t) -> li [] [ linkRadio (Set.member l model.lang) (Lang l) [ langIcon l, text t ] ]) GT.languages ]
- ] ]
- , formField "Platform(s)"
- [ div [ class "elm_dd_input", style "width" "500px" ] [ DD.view model.platDd Api.Normal
- (if Set.isEmpty model.plat
- then text "No platform selected"
- else span [] <| List.intersperse (text ", ") <| List.map (\(p,t) -> span [ style "white-space" "nowrap" ] [ platformIcon p, text t ]) <| List.filter (\(p,_) -> Set.member p model.plat) GT.platforms)
- <| \() -> [ ul [ style "columns" "2"] <| List.map (\(p,t) -> li [ classList [("separator", p == "web")] ] [ linkRadio (Set.member p model.plat) (Plat p) [ platformIcon p, text t ] ]) GT.platforms ]
- ] ]
- , formField "Media"
- [ table [] <| List.indexedMap (\i m ->
- let q = List.filter (\(s,_,_) -> m.medium == s) GT.media |> List.head |> Maybe.map (\(_,_,x) -> x) |> Maybe.withDefault False
- in tr []
- [ td [] [ inputSelect "" m.medium (MediaType i) [] <| (if m.medium == "unk" then [("unk", "- Add medium -")] else []) ++ List.map (\(a,b,_) -> (a,b)) GT.media ]
- , td [] [ if q then inputSelect "" m.qty (MediaQty i) [ style "width" "100px" ] <| List.map (\a -> (a,String.fromInt a)) <| List.range 1 20 else text "" ]
- , td [] [ if m.medium == "unk" then text "" else inputButton "remove" (MediaDel i) [] ]
- ]
- ) <| model.media ++ [{medium = "unk", qty = 0}]
- , if hasDuplicates (List.map (\m -> (m.medium, m.qty)) model.media)
- then b [ class "standout" ] [ text "List contains duplicates", br [] [] ]
- else text ""
- ]
-
- , if model.patch then text "" else
- formField "engine::Engine" [ A.view model.engineConf model.engine [] ]
- , if model.patch then text "" else
- formField "resolution::Resolution"
- [ A.view model.resoConf model.reso []
- , if resoParse model.reso.value == Nothing then b [ class "standout" ] [ text " Invalid resolution" ] else text ""
- ]
- , if model.patch then text "" else
- formField "voiced::Voiced" [ inputSelect "voiced" model.voiced Voiced [] GT.voiced ]
- , if model.patch then text "" else
- formField "ani_story::Animations"
- [ inputSelect "ani_story" model.ani_story AniStory [] GT.animated
- , if model.minage == 18 then text " <= story | ero scenes => " else text ""
- , if model.minage == 18 then inputSelect "" model.ani_ero AniEro [] GT.animated else text ""
- ]
- , if model.minage /= 18 then text "" else
- formField "" [ label [] [ inputCheck "" model.uncensored Uncensored, text " Uncensored (No mosaic or other optical censoring, only check if this release has erotic content)" ] ]
-
- , tr [ class "newpart" ] [ td [ colspan 2 ] [ text "External identifiers & links" ] ]
- , formField "gtin::JAN/UPC/EAN"
- [ inputText "gtin" model.gtin Gtin [pattern "[0-9]+"]
- , if not model.gtinValid then b [ class "standout" ] [ text "Invalid GTIN code" ] else text ""
- ]
- , formField "catalog::Catalog number" [ inputText "catalog" model.catalog Catalog GRE.valCatalog ]
- , formField "website::Website" [ inputText "website" model.website Website (style "width" "500px" :: GRE.valWebsite) ]
- , tr [ class "newpart" ] [ td [ colspan 2 ] [] ]
- , formField "External Links" [ Html.map ExtLinks (EL.view model.extlinks) ]
-
- , tr [ class "newpart" ] [ td [ colspan 2 ] [ text "Database relations" ] ]
- , formField "Visual novels"
- [ if List.isEmpty model.vn then b [ class "standout" ] [ text "No visual novels selected.", br [] [] ]
- else table [] <| List.indexedMap (\i v -> tr []
- [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| "v" ++ String.fromInt v.vid ++ ":" ] ]
- , td [] [ a [ href <| "/v" ++ String.fromInt v.vid ] [ text v.title ] ]
- , td [] [ inputButton "remove" (VNDel i) [] ]
- ]
- ) model.vn
- , A.view vnConfig model.vnAdd [placeholder "Add visual novel..."]
- ]
- , tr [ class "newpart" ] [ td [ colspan 2 ] [] ]
- , formField "Producers"
- [ table [ class "compact" ] <| List.indexedMap (\i p -> tr []
- [ td [ style "text-align" "right" ] [ b [ class "grayedout" ] [ text <| "p" ++ String.fromInt p.pid ++ ":" ] ]
- , td [] [ a [ href <| "/p" ++ String.fromInt p.pid ] [ text p.name ] ]
- , td [] [ inputSelect "" (p.developer, p.publisher) (ProdRole i) [style "width" "100px"] [((True,False), "Developer"), ((False,True), "Publisher"), ((True,True), "Both")] ]
- , td [] [ inputButton "remove" (ProdDel i) [] ]
- ]
- ) model.prod
- , A.view producerConfig model.prodAdd [placeholder "Add producer..."]
- ]
-
- , tr [ class "newpart" ] [ td [ colspan 2 ] [] ]
- , formField "notes::Notes"
- [ TP.view "notes" model.notes Notes 700 [] [ b [ class "standout" ] [ text " (English please!) " ] ]
- , text "Miscellaneous notes/comments, information that does not fit in the above fields. E.g.: Types of censoring or for which releases this patch applies."
- ]
- ]
-
-view : Model -> Html Msg
-view model =
- form_ Submit (model.state == Api.Loading)
- [ div [ class "mainbox" ]
- [ h1 [] [ text "General info" ]
- , viewGen model
- ]
- , div [ class "mainbox" ]
- [ fieldset [ class "submit" ]
- [ Html.map Editsum (Editsum.view model.editsum)
- , submitButton "Submit" model.state (isValid model)
- ]
- ]
- ]