summaryrefslogtreecommitdiff
path: root/elm/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'elm/Lib')
-rw-r--r--elm/Lib/Api.elm3
-rw-r--r--elm/Lib/Autocomplete.elm34
-rw-r--r--elm/Lib/Editsum.elm5
-rw-r--r--elm/Lib/Image.elm183
4 files changed, 221 insertions, 4 deletions
diff --git a/elm/Lib/Api.elm b/elm/Lib/Api.elm
index 4af28ea6..fd4a3a7e 100644
--- a/elm/Lib/Api.elm
+++ b/elm/Lib/Api.elm
@@ -45,14 +45,15 @@ showResponse res =
BadCurPass -> "Current password is invalid."
MailChange -> unexp
ImgFormat -> "Unrecognized image format, only JPEG and PNG are accepted."
- Image _ _ _ -> unexp
Releases _ -> unexp
BoardResult _ -> unexp
TagResult _ -> unexp
TraitResult _ -> unexp
VNResult _ -> unexp
ProducerResult _ -> unexp
+ StaffResult _ -> unexp
CharResult _ -> unexp
+ AnimeResult _ -> unexp
ImageResult _ -> unexp
diff --git a/elm/Lib/Autocomplete.elm b/elm/Lib/Autocomplete.elm
index 738f6008..5c5dd33d 100644
--- a/elm/Lib/Autocomplete.elm
+++ b/elm/Lib/Autocomplete.elm
@@ -9,7 +9,9 @@ module Lib.Autocomplete exposing
, traitSource
, vnSource
, producerSource
+ , staffSource
, charSource
+ , animeSource
, init
, clear
, update
@@ -35,7 +37,9 @@ import Gen.Tags as GT
import Gen.Traits as GTR
import Gen.VN as GV
import Gen.Producers as GP
+import Gen.Staff as GS
import Gen.Chars as GC
+import Gen.Anime as GA
type alias Config m a =
@@ -123,7 +127,7 @@ traitSource =
vnSource : SourceConfig m GApi.ApiVNResult
vnSource =
- { source = Endpoint (\s -> GV.send { search = s })
+ { source = Endpoint (\s -> GV.send { search = [s], hidden = False })
<| \x -> case x of
GApi.VNResult e -> Just e
_ -> Nothing
@@ -136,7 +140,7 @@ vnSource =
producerSource : SourceConfig m GApi.ApiProducerResult
producerSource =
- { source = Endpoint (\s -> GP.send { search = s })
+ { source = Endpoint (\s -> GP.send { search = [s], hidden = False })
<| \x -> case x of
GApi.ProducerResult e -> Just e
_ -> Nothing
@@ -147,6 +151,19 @@ producerSource =
}
+staffSource : SourceConfig m GApi.ApiStaffResult
+staffSource =
+ { source = Endpoint (\s -> GS.send { search = s })
+ <| \x -> case x of
+ GApi.StaffResult e -> Just e
+ _ -> Nothing
+ , view = \i ->
+ [ b [ class "grayedout" ] [ text <| "s" ++ String.fromInt i.id ++ ": " ]
+ , text i.name ]
+ , key = \i -> String.fromInt i.aid
+ }
+
+
charSource : SourceConfig m GApi.ApiCharResult
charSource =
{ source = Endpoint (\s -> GC.send { search = s })
@@ -164,6 +181,19 @@ charSource =
}
+animeSource : SourceConfig m GApi.ApiAnimeResult
+animeSource =
+ { source = Endpoint (\s -> GA.send { search = s })
+ <| \x -> case x of
+ GApi.AnimeResult e -> Just e
+ _ -> Nothing
+ , view = \i ->
+ [ b [ class "grayedout" ] [ text <| "a" ++ String.fromInt i.id ++ ": " ]
+ , text i.title ]
+ , key = \i -> String.fromInt i.id
+ }
+
+
type alias Model a =
{ visible : Bool
, value : String
diff --git a/elm/Lib/Editsum.elm b/elm/Lib/Editsum.elm
index 656441e8..20a51872 100644
--- a/elm/Lib/Editsum.elm
+++ b/elm/Lib/Editsum.elm
@@ -59,5 +59,8 @@ view model =
(if model.authmod then lockhid else [])
++
[ TP.view "" model.editsum Editsum 600 [rows 4, cols 50, minlength 2, maxlength 5000, required True]
- [ b [class "title"] [ text "Edit summary", b [class "standout"] [text " (English please!)"] ] ]
+ [ b [class "title"] [ text "Edit summary", b [class "standout"] [ text " (English please!)" ] ]
+ , br [] []
+ , text "Summarize the changes you have made, including links to source(s)."
+ ]
]
diff --git a/elm/Lib/Image.elm b/elm/Lib/Image.elm
new file mode 100644
index 00000000..31bab0b3
--- /dev/null
+++ b/elm/Lib/Image.elm
@@ -0,0 +1,183 @@
+module Lib.Image exposing (..)
+
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+import Process
+import Task
+import File exposing (File)
+import Lib.Html exposing (..)
+import Lib.Api as Api
+import Lib.Util exposing (imageUrl)
+import Gen.Api as GApi
+import Gen.Image as GI
+import Gen.ImageVote as GIV
+
+
+type State
+ = Normal
+ | Invalid
+ | NotFound
+ | Loading
+ | Error GApi.Response
+
+type alias Image =
+ { id : Maybe String
+ , img : Maybe GApi.ApiImageResult
+ , imgState : State
+ , saveState : Api.State
+ , saveTimer : Bool
+ }
+
+
+info : Maybe GApi.ApiImageResult -> Image
+info img =
+ { id = Maybe.map (\i -> i.id) img
+ , img = img
+ , imgState = Normal
+ , saveState = Api.Normal
+ , saveTimer = False
+ }
+
+
+-- Fetch image info from the ID
+new : Bool -> String -> (Image, Cmd Msg)
+new valid id =
+ ( { id = if id == "" then Nothing else Just id
+ , img = Nothing
+ , imgState = if id == "" then Normal else if valid then Loading else Invalid
+ , saveState = Api.Normal
+ , saveTimer = False
+ }
+ , if valid && id /= "" then GI.send { id = id } Loaded else Cmd.none
+ )
+
+
+-- Upload a new image from a form
+upload : Api.ImageType -> File -> (Image, Cmd Msg)
+upload t f =
+ ( { id = Nothing
+ , img = Nothing
+ , imgState = Loading
+ , saveState = Api.Normal
+ , saveTimer = False
+ }
+ , Api.postImage t f Loaded)
+
+
+type Msg
+ = Loaded GApi.Response
+ | MySex Int Bool
+ | MyVio Int Bool
+ | Save
+ | Saved GApi.Response
+
+
+update : Msg -> Image -> (Image, Cmd Msg)
+update msg model =
+ let
+ save m =
+ if m.saveTimer || Maybe.withDefault True (Maybe.map (\i -> i.token == Nothing || i.my_sexual == Nothing || i.my_violence == Nothing) m.img)
+ then (m, Cmd.none)
+ else ({ m | saveTimer = True }, Task.perform (always Save) (Process.sleep 1000))
+ in
+ case msg of
+ Loaded (GApi.ImageResult [i]) -> ({ model | id = Just i.id, img = Just i, imgState = Normal}, Cmd.none)
+ Loaded (GApi.ImageResult []) -> ({ model | imgState = NotFound}, Cmd.none)
+ Loaded e -> ({ model | imgState = Error e }, Cmd.none)
+
+ MySex v _ -> save { model | img = Maybe.map (\i -> { i | my_sexual = Just v }) model.img }
+ MyVio v _ -> save { model | img = Maybe.map (\i -> { i | my_violence = Just v }) model.img }
+
+ Save ->
+ case Maybe.map (\i -> (i.token, i.my_sexual, i.my_violence)) model.img of
+ Just (Just token, Just sex, Just vio) ->
+ ( { model | saveTimer = False, saveState = Api.Loading }
+ , GIV.send { votes = [{ id = Maybe.withDefault "" model.id, token = token, sexual = sex, violence = vio, overrule = False }] } Saved)
+ _ -> (model, Cmd.none)
+ Saved (GApi.Success) -> ({ model | saveState = Api.Normal}, Cmd.none)
+ Saved e -> ({ model | saveState = Api.Error e }, Cmd.none)
+
+
+
+isValid : Image -> Bool
+isValid img = img.imgState == Normal
+
+
+viewImg : Image -> Html m
+viewImg image =
+ case (image.imgState, image.img) of
+ (Loading, _) -> div [ class "spinner" ] []
+ (NotFound, _) -> b [ class "standout" ] [ text "Image not found." ]
+ (Invalid, _) -> b [ class "standout" ] [ text "Invalid image ID." ]
+ (Error e, _) -> b [ class "standout" ] [ text <| Api.showResponse e ]
+ (_, Nothing) -> text "No image."
+ (_, Just i) ->
+ let
+ maxWidth = toFloat <| if String.startsWith "sf" i.id then 136 else 10000
+ maxHeight = toFloat <| if String.startsWith "sf" i.id then 102 else 10000
+ sWidth = maxWidth / toFloat i.width
+ sHeight = maxHeight / toFloat i.height
+ scale = Basics.min 1 <| if sWidth < sHeight then sWidth else sHeight
+ imgWidth = round <| scale * toFloat i.width
+ imgHeight = round <| scale * toFloat i.height
+ in
+ -- TODO: Onclick iv.js support for screenshot thumbnails
+ label [ class "imghover", style "width" (String.fromInt imgWidth++"px"), style "height" (String.fromInt imgHeight++"px") ]
+ [ div [ class "imghover--visible" ]
+ [ if String.startsWith "sf" i.id
+ then a [ href (imageUrl i.id), attribute "data-iv" <| String.fromInt i.width ++ "x" ++ String.fromInt i.height ++ ":scr" ]
+ [ img [ src <| imageUrl <| String.replace "sf" "st" i.id ] [] ]
+ else img [ src <| imageUrl i.id ] []
+ , a [ class "imghover--overlay", href <| "/img/"++i.id ] <|
+ case (i.sexual_avg, i.violence_avg) of
+ (Just sex, Just vio) ->
+ -- XXX: These thresholds are subject to change, maybe just show the numbers here?
+ [ text <| if sex > 1.3 then "Explicit" else if sex > 0.4 then "Suggestive" else "Tame"
+ , text " / "
+ , text <| if vio > 1.3 then "Brutal" else if vio > 0.4 then "Violent" else "Safe"
+ , text <| " (" ++ String.fromInt i.votecount ++ ")"
+ ]
+ _ -> [ text "Not flagged" ]
+ ]
+ ]
+
+
+viewVote : Image -> Maybe (Html Msg)
+viewVote model =
+ let
+ rad i sex val = input
+ [ type_ "radio"
+ , tabindex 10
+ , required True
+ , onCheck <| (if sex then MySex else MyVio) val
+ , checked <| (if sex then i.my_sexual else i.my_violence) == Just val
+ , name <| "imgvote-" ++ (if sex then "sex" else "vio") ++ "-" ++ Maybe.withDefault "" model.id
+ ] []
+ vote i = table []
+ [ thead [] [ tr []
+ [ td [] [ text "Sexual ", if model.saveState == Api.Loading then span [ class "spinner" ] [] else text "" ]
+ , td [] [ text "Violence" ]
+ ] ]
+ , tfoot [] <|
+ case model.saveState of
+ Api.Error e -> [ tr [] [ td [ colspan 2 ] [ b [ class "standout" ] [ text (Api.showResponse e) ] ] ] ]
+ _ -> []
+ , tr []
+ [ td [ style "white-space" "nowrap" ]
+ [ label [] [ rad i True 0, text " Safe" ], br [] []
+ , label [] [ rad i True 1, text " Suggestive" ], br [] []
+ , label [] [ rad i True 2, text " Explicit" ]
+ ]
+ , td [ style "white-space" "nowrap" ]
+ [ label [] [ rad i False 0, text " Tame" ], br [] []
+ , label [] [ rad i False 1, text " Violent" ], br [] []
+ , label [] [ rad i False 2, text " Brutal" ]
+ ]
+ ]
+ ]
+ in case model.img of
+ Nothing -> Nothing
+ Just i ->
+ if i.token == Nothing then Nothing
+ else Just (vote i)