2020-10-28 18:51:01 +00:00
|
|
|
module Route exposing (Route(..), fromUrl, href, replaceUrl, routeToString)
|
2020-05-08 13:24:58 +00:00
|
|
|
|
|
|
|
import Browser.Navigation
|
|
|
|
import Html
|
|
|
|
import Html.Attributes
|
2020-10-28 18:51:01 +00:00
|
|
|
import Route.SearchQuery
|
2020-05-08 13:24:58 +00:00
|
|
|
import Url
|
2020-10-28 18:51:01 +00:00
|
|
|
import Url.Builder exposing (QueryParameter)
|
2020-05-08 13:24:58 +00:00
|
|
|
import Url.Parser exposing ((<?>))
|
|
|
|
import Url.Parser.Query
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- ROUTING
|
|
|
|
|
|
|
|
|
|
|
|
type Route
|
|
|
|
= NotFound
|
|
|
|
| Home
|
2020-10-28 23:38:46 +00:00
|
|
|
-- route | channel | (search) query | show | from | size | sort
|
2020-07-10 07:49:43 +00:00
|
|
|
| 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)
|
2020-05-08 13:24:58 +00:00
|
|
|
|
|
|
|
|
2020-10-28 18:51:01 +00:00
|
|
|
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
|
2020-05-08 13:24:58 +00:00
|
|
|
Url.Parser.oneOf
|
2020-10-28 18:51:01 +00:00
|
|
|
[ Url.Parser.map Home Url.Parser.top
|
|
|
|
, Url.Parser.map NotFound (Url.Parser.s "not-found")
|
|
|
|
, Url.Parser.map (withSearchQuery Packages)
|
2020-05-08 13:24:58 +00:00
|
|
|
(Url.Parser.s "packages"
|
2020-05-11 20:42:57 +00:00
|
|
|
<?> Url.Parser.Query.string "channel"
|
2020-06-10 12:15:54 +00:00
|
|
|
<?> Url.Parser.Query.string "show"
|
2020-05-11 19:56:10 +00:00
|
|
|
<?> Url.Parser.Query.int "from"
|
|
|
|
<?> Url.Parser.Query.int "size"
|
2020-07-10 07:49:43 +00:00
|
|
|
<?> Url.Parser.Query.string "sort"
|
2020-05-08 13:24:58 +00:00
|
|
|
)
|
2020-10-28 18:51:01 +00:00
|
|
|
, Url.Parser.map (withSearchQuery Options)
|
2020-05-08 13:24:58 +00:00
|
|
|
(Url.Parser.s "options"
|
2020-05-11 20:42:57 +00:00
|
|
|
<?> Url.Parser.Query.string "channel"
|
2020-06-10 12:15:54 +00:00
|
|
|
<?> Url.Parser.Query.string "show"
|
2020-05-11 19:56:10 +00:00
|
|
|
<?> Url.Parser.Query.int "from"
|
|
|
|
<?> Url.Parser.Query.int "size"
|
2020-07-10 07:49:43 +00:00
|
|
|
<?> Url.Parser.Query.string "sort"
|
2020-05-08 13:24:58 +00:00
|
|
|
)
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- 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 }
|
2020-10-28 18:51:01 +00:00
|
|
|
Url.Parser.parse (parser url) url
|
2020-05-08 13:24:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- INTERNAL
|
|
|
|
|
|
|
|
|
|
|
|
routeToString : Route -> String
|
2020-10-28 18:51:01 +00:00
|
|
|
routeToString =
|
2020-05-08 13:24:58 +00:00
|
|
|
let
|
2020-10-28 18:51:01 +00:00
|
|
|
buildString ( path, query, searchQuery ) =
|
|
|
|
Route.SearchQuery.absolute path query <|
|
|
|
|
Maybe.withDefault [] <|
|
|
|
|
Maybe.map List.singleton searchQuery
|
2020-05-08 13:24:58 +00:00
|
|
|
in
|
2020-10-28 18:51:01 +00:00
|
|
|
buildString << routeToPieces
|
2020-05-08 13:24:58 +00:00
|
|
|
|
|
|
|
|
2020-10-28 18:51:01 +00:00
|
|
|
routeToPieces : Route -> ( List String, List QueryParameter, Maybe ( String, Route.SearchQuery.SearchQuery ) )
|
2020-05-08 13:24:58 +00:00
|
|
|
routeToPieces page =
|
2020-10-28 18:51:01 +00:00
|
|
|
let
|
|
|
|
channelQ =
|
|
|
|
Maybe.map (Url.Builder.string "channel")
|
2020-05-08 13:24:58 +00:00
|
|
|
|
2020-10-28 18:51:01 +00:00
|
|
|
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
|
|
|
|
)
|