Update part10 to do advanced search options
This commit is contained in:
@@ -1,23 +1,12 @@
|
|||||||
module ElmHub exposing (..)
|
module ElmHub exposing (..)
|
||||||
|
|
||||||
import Html exposing (..)
|
import Html exposing (..)
|
||||||
import Html.Attributes exposing (class, target, href, defaultValue, type', checked)
|
import Html.Attributes exposing (class, target, href, defaultValue, type', checked, placeholder, value)
|
||||||
import Html.Events exposing (..)
|
import Html.Events exposing (..)
|
||||||
import Html.App as Html
|
import Html.App as Html
|
||||||
import Auth
|
import Auth
|
||||||
import Json.Decode exposing (Decoder)
|
import Json.Decode exposing (Decoder)
|
||||||
import Json.Decode.Pipeline exposing (..)
|
import Json.Decode.Pipeline exposing (..)
|
||||||
import String
|
|
||||||
|
|
||||||
|
|
||||||
getQueryString : String -> String
|
|
||||||
getQueryString query =
|
|
||||||
-- See https://developer.github.com/v3/search/#example for how to customize!
|
|
||||||
"access_token="
|
|
||||||
++ Auth.token
|
|
||||||
++ "&q="
|
|
||||||
++ query
|
|
||||||
++ "+language:elm&sort=stars&order=desc"
|
|
||||||
|
|
||||||
|
|
||||||
responseDecoder : Decoder (List SearchResult)
|
responseDecoder : Decoder (List SearchResult)
|
||||||
@@ -43,9 +32,9 @@ type alias Model =
|
|||||||
|
|
||||||
type alias SearchOptions =
|
type alias SearchOptions =
|
||||||
{ sort : String
|
{ sort : String
|
||||||
, order : String
|
, ascending : Bool
|
||||||
, searchIn : List String
|
, searchIn : List String
|
||||||
, includeForks : Bool
|
, searchInDescription : Bool
|
||||||
, userFilter : String
|
, userFilter : String
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,10 +52,10 @@ initialModel =
|
|||||||
, results = []
|
, results = []
|
||||||
, errorMessage = Nothing
|
, errorMessage = Nothing
|
||||||
, options =
|
, options =
|
||||||
{ sort = ""
|
{ sort = "stars"
|
||||||
, order = ""
|
, ascending = False
|
||||||
, searchIn = []
|
, searchIn = []
|
||||||
, includeForks = True
|
, searchInDescription = True
|
||||||
, userFilter = ""
|
, userFilter = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +78,7 @@ update searchFeed msg model =
|
|||||||
--
|
--
|
||||||
-- HINT: calling updateOptions will save a lot of time here!
|
-- HINT: calling updateOptions will save a lot of time here!
|
||||||
Search ->
|
Search ->
|
||||||
( model, searchFeed (getQueryString model.query) )
|
( model, searchFeed (getQueryString model) )
|
||||||
|
|
||||||
SetQuery query ->
|
SetQuery query ->
|
||||||
( { model | query = query }, Cmd.none )
|
( { model | query = query }, Cmd.none )
|
||||||
@@ -115,6 +104,22 @@ update searchFeed msg model =
|
|||||||
( model, Cmd.none )
|
( model, Cmd.none )
|
||||||
|
|
||||||
|
|
||||||
|
updateOptions : OptionsMsg -> SearchOptions -> SearchOptions
|
||||||
|
updateOptions optionsMsg options =
|
||||||
|
case optionsMsg of
|
||||||
|
SetSort sort ->
|
||||||
|
{ options | sort = sort }
|
||||||
|
|
||||||
|
SetAscending ascending ->
|
||||||
|
{ options | ascending = ascending }
|
||||||
|
|
||||||
|
SetSearchInDescription searchInDescription ->
|
||||||
|
{ options | searchInDescription = searchInDescription }
|
||||||
|
|
||||||
|
SetUserFilter userFilter ->
|
||||||
|
{ options | userFilter = userFilter }
|
||||||
|
|
||||||
|
|
||||||
view : Model -> Html Msg
|
view : Model -> Html Msg
|
||||||
view model =
|
view model =
|
||||||
div [ class "content" ]
|
div [ class "content" ]
|
||||||
@@ -122,9 +127,13 @@ view model =
|
|||||||
[ h1 [] [ text "ElmHub" ]
|
[ h1 [] [ text "ElmHub" ]
|
||||||
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
, span [ class "tagline" ] [ text "Like GitHub, but for Elm things." ]
|
||||||
]
|
]
|
||||||
-- TODO call viewOptions here. Use Html.map to avoid a type mismatch!
|
, div [ class "search" ]
|
||||||
, input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
|
[ text "TODO replace this text node with a call to viewOptions. Use Html.map to avoid a type mismatch!"
|
||||||
, button [ class "search-button", onClick Search ] [ text "Search" ]
|
, div [ class "search-input" ]
|
||||||
|
[ input [ class "search-query", onInput SetQuery, defaultValue model.query ] []
|
||||||
|
, button [ class "search-button", onClick Search ] [ text "Search" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
, viewErrorMessage model.errorMessage
|
, viewErrorMessage model.errorMessage
|
||||||
, ul [ class "results" ] (List.map viewSearchResult model.results)
|
, ul [ class "results" ] (List.map viewSearchResult model.results)
|
||||||
]
|
]
|
||||||
@@ -153,39 +162,40 @@ viewSearchResult result =
|
|||||||
|
|
||||||
type OptionsMsg
|
type OptionsMsg
|
||||||
= SetSort String
|
= SetSort String
|
||||||
| SetOrder String
|
| SetAscending Bool
|
||||||
| SetSearchIn (List String)
|
| SetSearchInDescription Bool
|
||||||
| SetIncludeForks Bool
|
|
||||||
| SetUserFilter String
|
| SetUserFilter String
|
||||||
|
|
||||||
|
|
||||||
updateOptions : OptionsMsg -> SearchOptions -> SearchOptions
|
|
||||||
updateOptions optionsMsg options =
|
|
||||||
case optionsMsg of
|
|
||||||
SetSort sort ->
|
|
||||||
{ options | sort = sort }
|
|
||||||
|
|
||||||
SetOrder order ->
|
|
||||||
{ options | order = order }
|
|
||||||
|
|
||||||
SetSearchIn searchIn ->
|
|
||||||
{ options | searchIn = searchIn }
|
|
||||||
|
|
||||||
SetIncludeForks includeForks ->
|
|
||||||
{ options | includeForks = includeForks }
|
|
||||||
|
|
||||||
SetUserFilter userFilter ->
|
|
||||||
{ options | userFilter = userFilter }
|
|
||||||
|
|
||||||
|
|
||||||
viewOptions : SearchOptions -> Html OptionsMsg
|
viewOptions : SearchOptions -> Html OptionsMsg
|
||||||
viewOptions model =
|
viewOptions opts =
|
||||||
div []
|
div [ class "search-options" ]
|
||||||
[ input [ type' "text", defaultValue model.sort, onInput SetSort ] []
|
[ div [ class "search-option" ]
|
||||||
, input [ type' "text", defaultValue model.order, onInput SetOrder ] []
|
[ label [ class "top-label" ] [ text "Sort by" ]
|
||||||
, input [ type' "text", defaultValue (String.join " " model.searchIn) ] []
|
, select [ onChange SetSort, value opts.sort ]
|
||||||
, input [ type' "checkbox", checked model.includeForks ] []
|
[ option [ value "stars" ] [ text "Stars" ]
|
||||||
, input [ type' "text", defaultValue model.userFilter, onInput SetUserFilter ] []
|
, option [ value "forks" ] [ text "Forks" ]
|
||||||
|
, option [ value "updated" ] [ text "Updated" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
, div [ class "search-option" ]
|
||||||
|
[ label [ class "top-label" ] [ text "Owned by" ]
|
||||||
|
, input
|
||||||
|
[ type' "text"
|
||||||
|
, placeholder "Enter a username"
|
||||||
|
, defaultValue opts.userFilter
|
||||||
|
, onInput SetUserFilter
|
||||||
|
]
|
||||||
|
[]
|
||||||
|
]
|
||||||
|
, label [ class "search-option" ]
|
||||||
|
[ input [ type' "checkbox", checked opts.ascending, onCheck SetAscending ] []
|
||||||
|
, text "Sort ascending"
|
||||||
|
]
|
||||||
|
, label [ class "search-option" ]
|
||||||
|
[ input [ type' "checkbox", checked opts.searchInDescription, onCheck SetSearchInDescription ] []
|
||||||
|
, text "Search in description"
|
||||||
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -197,3 +207,31 @@ decodeGithubResponse value =
|
|||||||
|
|
||||||
Err err ->
|
Err err ->
|
||||||
HandleSearchError (Just err)
|
HandleSearchError (Just err)
|
||||||
|
|
||||||
|
|
||||||
|
onChange : (String -> msg) -> Attribute msg
|
||||||
|
onChange toMsg =
|
||||||
|
on "change" (Json.Decode.map toMsg Html.Events.targetValue)
|
||||||
|
|
||||||
|
|
||||||
|
getQueryString : Model -> String
|
||||||
|
getQueryString model =
|
||||||
|
-- See https://developer.github.com/v3/search/#example for how to customize!
|
||||||
|
"access_token="
|
||||||
|
++ Auth.token
|
||||||
|
++ "&q="
|
||||||
|
++ model.query
|
||||||
|
++ (if model.options.searchInDescription then
|
||||||
|
"+in:name,description"
|
||||||
|
else
|
||||||
|
"+in:name"
|
||||||
|
)
|
||||||
|
++ "+language:elm"
|
||||||
|
++ "&sort="
|
||||||
|
++ model.options.sort
|
||||||
|
++ "&order="
|
||||||
|
++ (if model.options.ascending then
|
||||||
|
"asc"
|
||||||
|
else
|
||||||
|
"desc"
|
||||||
|
)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ main =
|
|||||||
Html.program
|
Html.program
|
||||||
{ view = view
|
{ view = view
|
||||||
, update = update githubSearch
|
, update = update githubSearch
|
||||||
, init = ( initialModel, githubSearch (getQueryString initialModel.query) )
|
, init = ( initialModel, githubSearch (getQueryString initialModel) )
|
||||||
, subscriptions = \_ -> githubResponse decodeResponse
|
, subscriptions = \_ -> githubResponse decodeResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -99,3 +99,41 @@ button:focus, input:focus {
|
|||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-options {
|
||||||
|
position: relative;
|
||||||
|
float: right;
|
||||||
|
width: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-option {
|
||||||
|
display: block;
|
||||||
|
float: left;
|
||||||
|
width: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-option input[type="text"] {
|
||||||
|
padding: 5px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search:after {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-label {
|
||||||
|
display: block;
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user