import Html exposing (..)
import Html.Events exposing (..)
import Html.Attributes exposing (href, style, src)
import Task exposing (Task)
import Http exposing (Error)
import JavaScript.Decode exposing (..)
-- Operator from Clojure
(>!) : a -> Stream.Input a -> Stream.Message
(>!) a input' = Stream.message input'.address a
-- Javascript Decoding Helper
andMap : Decoder (a -> b) -> Decoder a -> Decoder b
andMap = object2 (<|)
-- Model + Javascript Parsing
type alias RedditPostData =
{ url : String
, title : String
, score : Int
}
redditPostData : Decoder RedditPostData
redditPostData = RedditPostData
`map` ("url" := string)
`andMap` ("title" := string)
`andMap` ("score" := int)
type alias RedditPost =
{ data : RedditPostData }
redditPost : Decoder RedditPost
redditPost = RedditPost
`map` ("data" := redditPostData )
type alias RedditListingData =
{ children : List RedditPost }
redditListingData : Decoder RedditListingData
redditListingData = RedditListingData
`map` ("children" := list redditPost)
type alias RedditListing =
{ data : RedditListingData }
redditListing : Decoder RedditListing
redditListing = RedditListing
`map` ("data" := redditListingData)
testRedditListing : RedditListing
testRedditListing =
{ data = { children = [] } }
-- The Reddit Homepage!
redditUrl : String
redditUrl =
"https://www.reddit.com/.json"
-- The main promise
requestListing : String -> Task Error RedditListing
requestListing url =
Http.get redditListing url
-- The query we send
input query : Stream.Input String
-- The results from the query
input results : Stream (Result Error RedditListing)
input results from
Stream.map requestListing query.stream
-- VIEW
-- View an individual Reddit post
viewPost : RedditPost -> Html
viewPost { data } =
let
scoreStyle = style
[("height", "50px")
,("flex", "1")
,("align-self", "center")
]
itemStyle = style
[("display", "flex")
,("margin-bottom", "10px")
]
linkStyle = style
[("flex", "8")
,("align-self", "flex-start")
]
in
li [ itemStyle ]
[ div [ scoreStyle ]
[ text (toString data.score) ]
,
a
[ linkStyle
, href data.url
]
[ div [] [text data.title] ]
]
elmLogo : Html
elmLogo =
let
logoStyle = style
[("height", "50px")
,("width", "50px")
,("min-height", "40px")
,("min-width", "40px")
,("flex", "1")
]
in
img
[ src "http://elm-lang.org/logo.svg"
, logoStyle
][]
clientHeader : Html
clientHeader =
let
headerStyle = style
[ ("display", "flex")
, ("align-items", "center")
]
textStyle = style
[ ("flex", "8") ]
in
header [ headerStyle ]
[ elmLogo
, div [ textStyle ] [ text "Reddit Client in Elm" ]
]
-- Global view function
view : Result Error RedditListing -> Html
view listingResult = case listingResult of
Err error ->
button
[ onClick (redditUrl >! query) ]
[ text "Get Reddit Front Page" ]
Ok listing ->
div []
[ clientHeader
, ul []
(List.map viewPost listing.data.children)
]
-- Main Function
main : Varying Html
main =
Varying.map view
(Varying.fromStream (Err Http.Timeout) results)