aux-search/src/Route.elm

147 lines
4.2 KiB
Elm
Raw Normal View History

module Route exposing (Route(..), fromUrl, href, replaceUrl, routeToString)
import Browser.Navigation
import Html
import Html.Attributes
import Route.SearchQuery
import Url
import Url.Builder exposing (QueryParameter)
import Url.Parser exposing ((<?>))
import Url.Parser.Query
-- ROUTING
type Route
= NotFound
| Home
-- route | channel | (search) query | show | from | size | sort
| Packages (Maybe String) (Maybe String) (Maybe String) (Maybe Int) (Maybe Int) (Maybe String)
| Options (Maybe String) (Maybe String) (Maybe String) (Maybe Int) (Maybe Int) (Maybe String)
parser : Url.Url -> Url.Parser.Parser (Route -> msg) msg
parser url =
let
rawQuery =
Route.SearchQuery.toRawQuery url
withSearchQuery : (a -> Maybe String -> b) -> a -> b
withSearchQuery f channel =
f channel <|
Maybe.andThen Route.SearchQuery.searchQueryToString <|
Maybe.andThen (Route.SearchQuery.searchString "query") rawQuery
in
Url.Parser.oneOf
[ Url.Parser.map Home Url.Parser.top
, Url.Parser.map NotFound (Url.Parser.s "not-found")
, Url.Parser.map (withSearchQuery Packages)
(Url.Parser.s "packages"
2020-05-11 20:42:57 +00:00
<?> Url.Parser.Query.string "channel"
<?> Url.Parser.Query.string "show"
2020-05-11 19:56:10 +00:00
<?> Url.Parser.Query.int "from"
<?> Url.Parser.Query.int "size"
<?> Url.Parser.Query.string "sort"
)
, Url.Parser.map (withSearchQuery Options)
(Url.Parser.s "options"
2020-05-11 20:42:57 +00:00
<?> Url.Parser.Query.string "channel"
<?> Url.Parser.Query.string "show"
2020-05-11 19:56:10 +00:00
<?> Url.Parser.Query.int "from"
<?> Url.Parser.Query.int "size"
<?> Url.Parser.Query.string "sort"
)
]
-- PUBLIC HELPERS
href : Route -> Html.Attribute msg
href targetRoute =
Html.Attributes.href (routeToString targetRoute)
replaceUrl : Browser.Navigation.Key -> Route -> Cmd msg
replaceUrl navKey route =
Browser.Navigation.replaceUrl navKey (routeToString route)
fromUrl : Url.Url -> Maybe Route
fromUrl url =
-- The RealWorld spec treats the fragment like a path.
-- This makes it *literally* the path, so we can proceed
-- with parsing as if it had been a normal path all along.
--{ url | path = Maybe.withDefault "" url.fragment, fragment = Nothing }
Url.Parser.parse (parser url) url
-- INTERNAL
routeToString : Route -> String
routeToString =
let
buildString ( path, query, searchQuery ) =
Route.SearchQuery.absolute path query <|
Maybe.withDefault [] <|
Maybe.map List.singleton searchQuery
in
buildString << routeToPieces
routeToPieces : Route -> ( List String, List QueryParameter, Maybe ( String, Route.SearchQuery.SearchQuery ) )
routeToPieces page =
let
channelQ =
Maybe.map (Url.Builder.string "channel")
queryQ =
Maybe.map (Route.SearchQuery.toSearchQuery "query")
showQ =
Maybe.map (Url.Builder.string "show")
fromQ =
Maybe.map (Url.Builder.int "from")
sizeQ =
Maybe.map (Url.Builder.int "size")
sortQ =
Maybe.map (Url.Builder.string "sort")
in
(\( path, urlQ, searchQuery ) -> ( path, List.filterMap identity urlQ, searchQuery )) <|
case page of
Home ->
( [], [], Nothing )
NotFound ->
( [ "not-found" ], [], Nothing )
Packages channel query show from size sort ->
( [ "packages" ]
, [ channelQ channel
, showQ show
, fromQ from
, sizeQ size
, sortQ sort
]
, queryQ query
)
Options channel query show from size sort ->
( [ "options" ]
, [ channelQ channel
, showQ show
, fromQ from
, sizeQ size
, sortQ sort
]
, queryQ query
)