Add part3
This commit is contained in:
1
part3/elm-stuff/packages/evancz/url-parser/2.0.1/.gitignore
vendored
Normal file
1
part3/elm-stuff/packages/evancz/url-parser/2.0.1/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
elm-stuff
|
||||
27
part3/elm-stuff/packages/evancz/url-parser/2.0.1/LICENSE
vendored
Normal file
27
part3/elm-stuff/packages/evancz/url-parser/2.0.1/LICENSE
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2016, Evan Czaplicki
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the {organization} nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
67
part3/elm-stuff/packages/evancz/url-parser/2.0.1/README.md
vendored
Normal file
67
part3/elm-stuff/packages/evancz/url-parser/2.0.1/README.md
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# URL Parser
|
||||
|
||||
This library helps you turn URLs into nicely structured data.
|
||||
|
||||
It is designed to be used with `elm-lang/navigation` to help folks create single-page applications (SPAs) where you manage browser navigation yourself.
|
||||
|
||||
> **Note:** This library is meant to serve as a baseline for future URL parsers. For example, it does not handle query parameters and hashes right now. It is more to (1) get folks started using URL parsers and (2) help us gather data on exactly which scenarios people face.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Here is a simplified REPL session showing a parser in action:
|
||||
|
||||
```elm
|
||||
> import UrlParser exposing ((</>), s, int, string, parseHash)
|
||||
|
||||
> parseHash (s "blog" </> int) { ... , hash = "#blog/42" }
|
||||
Just 42
|
||||
|
||||
> parseHash (s "blog" </> int) { ... , hash = "#/blog/13" }
|
||||
Just 13
|
||||
|
||||
> parseHash (s "blog" </> int) { ... , hash = "#/blog/hello" }
|
||||
Nothing
|
||||
|
||||
> parseHash (s "search" </> string) { ... , hash = "#search/dogs" }
|
||||
Just "dogs"
|
||||
|
||||
> parseHash (s "search" </> string) { ... , hash = "#/search/13" }
|
||||
Just "13"
|
||||
|
||||
> parseHash (s "search" </> string) { ... , hash = "#/search" }
|
||||
Nothing
|
||||
```
|
||||
|
||||
Normally you have to put many of these parsers to handle all possible pages though! The following parser works on URLs like `/blog/42` and `/search/badger`:
|
||||
|
||||
```elm
|
||||
import UrlParser exposing (Parser, (</>), s, int, string, map, oneOf, parseHash)
|
||||
|
||||
type Route = Blog Int | Search String
|
||||
|
||||
route : Parser (Route -> a) a
|
||||
route =
|
||||
oneOf
|
||||
[ map Blog (s "blog" </> int)
|
||||
, map Search (s "search" </> string)
|
||||
]
|
||||
|
||||
-- parseHash route { ... , hash = "#/blog/58" } == Just (Blog 58)
|
||||
-- parseHash route { ... , hash = "#/search/cat" } == Just (Search "cat")
|
||||
-- parseHash route { ... , hash = "#/search/31" } == Just (Search "31")
|
||||
-- parseHash route { ... , hash = "#/blog/cat" } == Nothing
|
||||
-- parseHash route { ... , hash = "#/blog" } == Nothing
|
||||
```
|
||||
|
||||
Notice that we are turning URLs into nice [union types](https://guide.elm-lang.org/types/union_types.html), so we can use `case` expressions to work with them in a nice way.
|
||||
|
||||
Check out the `examples/` directory of this repo to see this in use with `elm-lang/navigation`.
|
||||
|
||||
|
||||
## Background
|
||||
|
||||
I first saw this general idea in Chris Done’s [formatting][] library. Based on that, Noah and I outlined the API you see in this library. Noah then found Rudi Grinberg’s [post][] about type safe routing in OCaml. It was exactly what we were going for. We had even used the names `s` and `(</>)` in our draft API! In the end, we ended up using the “final encoding” of the EDSL that had been left as an exercise for the reader. Very fun to work through!
|
||||
|
||||
[formatting]: http://chrisdone.com/posts/formatting
|
||||
[post]: http://rgrinberg.com/posts/primitive-type-safe-routing/
|
||||
18
part3/elm-stuff/packages/evancz/url-parser/2.0.1/elm-package.json
vendored
Normal file
18
part3/elm-stuff/packages/evancz/url-parser/2.0.1/elm-package.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": "2.0.1",
|
||||
"summary": "Parse URLs into nicely structured data, useful for navigation / \"SPA routing\"",
|
||||
"repository": "https://github.com/evancz/url-parser.git",
|
||||
"license": "BSD3",
|
||||
"source-directories": [
|
||||
"src"
|
||||
],
|
||||
"exposed-modules": [
|
||||
"UrlParser"
|
||||
],
|
||||
"dependencies": {
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
"elm-lang/http": "1.0.0 <= v < 2.0.0",
|
||||
"elm-lang/navigation": "2.0.0 <= v < 3.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
128
part3/elm-stuff/packages/evancz/url-parser/2.0.1/examples/Example.elm
vendored
Normal file
128
part3/elm-stuff/packages/evancz/url-parser/2.0.1/examples/Example.elm
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
import Html exposing (Html, a, button, code, div, h1, li, text, ul)
|
||||
import Html.Attributes exposing (href)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Navigation
|
||||
import UrlParser as Url exposing ((</>), (<?>), s, int, stringParam, top)
|
||||
|
||||
|
||||
|
||||
main =
|
||||
Navigation.program UrlChange
|
||||
{ init = init
|
||||
, view = view
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- MODEL
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ history : List (Maybe Route)
|
||||
}
|
||||
|
||||
|
||||
init : Navigation.Location -> ( Model, Cmd Msg )
|
||||
init location =
|
||||
( Model [Url.parsePath route location]
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- URL PARSING
|
||||
|
||||
|
||||
type Route
|
||||
= Home
|
||||
| BlogList (Maybe String)
|
||||
| BlogPost Int
|
||||
|
||||
|
||||
route : Url.Parser (Route -> a) a
|
||||
route =
|
||||
Url.oneOf
|
||||
[ Url.map Home top
|
||||
, Url.map BlogList (s "blog" <?> stringParam "search")
|
||||
, Url.map BlogPost (s "blog" </> int)
|
||||
]
|
||||
|
||||
|
||||
|
||||
-- UPDATE
|
||||
|
||||
|
||||
type Msg
|
||||
= NewUrl String
|
||||
| UrlChange Navigation.Location
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
NewUrl url ->
|
||||
( model
|
||||
, Navigation.newUrl url
|
||||
)
|
||||
|
||||
UrlChange location ->
|
||||
( { model | history = Url.parsePath route location :: model.history }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
|
||||
-- SUBSCRIPTIONS
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
Sub.none
|
||||
|
||||
|
||||
|
||||
-- VIEW
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div []
|
||||
[ h1 [] [ text "Links" ]
|
||||
, ul [] (List.map viewLink [ "/", "/blog/", "/blog/42", "/blog/37", "/blog/?search=cats" ])
|
||||
, h1 [] [ text "History" ]
|
||||
, ul [] (List.map viewRoute model.history)
|
||||
]
|
||||
|
||||
|
||||
viewLink : String -> Html Msg
|
||||
viewLink url =
|
||||
li [] [ button [ onClick (NewUrl url) ] [ text url ] ]
|
||||
|
||||
|
||||
viewRoute : Maybe Route -> Html msg
|
||||
viewRoute maybeRoute =
|
||||
case maybeRoute of
|
||||
Nothing ->
|
||||
li [] [ text "Invalid URL"]
|
||||
|
||||
Just route ->
|
||||
li [] [ code [] [ text (routeToString route) ] ]
|
||||
|
||||
|
||||
routeToString : Route -> String
|
||||
routeToString route =
|
||||
case route of
|
||||
Home ->
|
||||
"home"
|
||||
|
||||
BlogList Nothing ->
|
||||
"list all blog posts"
|
||||
|
||||
BlogList (Just search) ->
|
||||
"search for " ++ Http.encodeUri search
|
||||
|
||||
BlogPost id ->
|
||||
"show blog " ++ toString id
|
||||
12
part3/elm-stuff/packages/evancz/url-parser/2.0.1/examples/README.md
vendored
Normal file
12
part3/elm-stuff/packages/evancz/url-parser/2.0.1/examples/README.md
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
# Run the Examples
|
||||
|
||||
To run the examples in this folder, follow the following steps:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/evancz/url-parser.git
|
||||
cd url-parser
|
||||
cd examples
|
||||
elm-reactor
|
||||
```
|
||||
|
||||
This will navigate into the `examples/` directory and start `elm-reactor`. From here, go to [http://localhost:8000](http://localhost:8000) and start clicking on `.elm` files to see them in action.
|
||||
18
part3/elm-stuff/packages/evancz/url-parser/2.0.1/examples/elm-package.json
vendored
Normal file
18
part3/elm-stuff/packages/evancz/url-parser/2.0.1/examples/elm-package.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"summary": "Examples of using evancz/url-parser",
|
||||
"repository": "http://github.com/user/project.git",
|
||||
"license": "BSD-3-Clause",
|
||||
"source-directories": [
|
||||
"."
|
||||
],
|
||||
"exposed-modules": [],
|
||||
"dependencies": {
|
||||
"elm-lang/core": "5.0.0 <= v < 6.0.0",
|
||||
"elm-lang/html": "2.0.0 <= v < 3.0.0",
|
||||
"elm-lang/http": "1.0.0 <= v < 2.0.0",
|
||||
"elm-lang/navigation": "2.0.0 <= v < 3.0.0",
|
||||
"evancz/url-parser": "2.0.0 <= v < 3.0.0"
|
||||
},
|
||||
"elm-version": "0.18.0 <= v < 0.19.0"
|
||||
}
|
||||
414
part3/elm-stuff/packages/evancz/url-parser/2.0.1/src/UrlParser.elm
vendored
Normal file
414
part3/elm-stuff/packages/evancz/url-parser/2.0.1/src/UrlParser.elm
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
module UrlParser exposing
|
||||
( Parser, string, int, s
|
||||
, (</>), map, oneOf, top, custom
|
||||
, QueryParser, (<?>), stringParam, intParam, customParam
|
||||
, parsePath, parseHash
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
# Primitives
|
||||
@docs Parser, string, int, s
|
||||
|
||||
# Path Parses
|
||||
@docs (</>), map, oneOf, top, custom
|
||||
|
||||
# Query Parameter Parsers
|
||||
@docs QueryParser, (<?>), stringParam, intParam, customParam
|
||||
|
||||
# Run a Parser
|
||||
@docs parsePath, parseHash
|
||||
|
||||
-}
|
||||
|
||||
import Dict exposing (Dict)
|
||||
import Http
|
||||
import Navigation
|
||||
|
||||
|
||||
|
||||
-- PARSERS
|
||||
|
||||
|
||||
{-| Turn URLs like `/blog/42/cat-herding-techniques` into nice Elm data.
|
||||
-}
|
||||
type Parser a b =
|
||||
Parser (State a -> List (State b))
|
||||
|
||||
|
||||
type alias State value =
|
||||
{ visited : List String
|
||||
, unvisited : List String
|
||||
, params : Dict String String
|
||||
, value : value
|
||||
}
|
||||
|
||||
|
||||
|
||||
-- PARSE SEGMENTS
|
||||
|
||||
|
||||
{-| Parse a segment of the path as a `String`.
|
||||
|
||||
parsePath string location
|
||||
-- /alice/ ==> Just "alice"
|
||||
-- /bob ==> Just "bob"
|
||||
-- /42/ ==> Just "42"
|
||||
-}
|
||||
string : Parser (String -> a) a
|
||||
string =
|
||||
custom "STRING" Ok
|
||||
|
||||
|
||||
{-| Parse a segment of the path as an `Int`.
|
||||
|
||||
parsePath int location
|
||||
-- /alice/ ==> Nothing
|
||||
-- /bob ==> Nothing
|
||||
-- /42/ ==> Just 42
|
||||
-}
|
||||
int : Parser (Int -> a) a
|
||||
int =
|
||||
custom "NUMBER" String.toInt
|
||||
|
||||
|
||||
{-| Parse a segment of the path if it matches a given string.
|
||||
|
||||
s "blog" -- can parse /blog/
|
||||
-- but not /glob/ or /42/ or anything else
|
||||
-}
|
||||
s : String -> Parser a a
|
||||
s str =
|
||||
Parser <| \{ visited, unvisited, params, value } ->
|
||||
case unvisited of
|
||||
[] ->
|
||||
[]
|
||||
|
||||
next :: rest ->
|
||||
if next == str then
|
||||
[ State (next :: visited) rest params value ]
|
||||
|
||||
else
|
||||
[]
|
||||
|
||||
|
||||
{-| Create a custom path segment parser. Here is how it is used to define the
|
||||
`int` and `string` parsers:
|
||||
|
||||
int =
|
||||
custom "NUMBER" String.toInt
|
||||
|
||||
string =
|
||||
custom "STRING" Ok
|
||||
|
||||
You can use it to define something like “only CSS files” like this:
|
||||
|
||||
css : Parser (String -> a) a
|
||||
css =
|
||||
custom "CSS_FILE" <| \segment ->
|
||||
if String.endsWith ".css" then
|
||||
Ok segment
|
||||
else
|
||||
Err "Does not end with .css"
|
||||
-}
|
||||
custom : String -> (String -> Result String a) -> Parser (a -> b) b
|
||||
custom tipe stringToSomething =
|
||||
Parser <| \{ visited, unvisited, params, value } ->
|
||||
case unvisited of
|
||||
[] ->
|
||||
[]
|
||||
|
||||
next :: rest ->
|
||||
case stringToSomething next of
|
||||
Ok nextValue ->
|
||||
[ State (next :: visited) rest params (value nextValue) ]
|
||||
|
||||
Err msg ->
|
||||
[]
|
||||
|
||||
|
||||
|
||||
-- COMBINING PARSERS
|
||||
|
||||
|
||||
{-| Parse a path with multiple segments.
|
||||
|
||||
parsePath (s "blog" </> int) location
|
||||
-- /blog/35/ ==> Just 35
|
||||
-- /blog/42 ==> Just 42
|
||||
-- /blog/ ==> Nothing
|
||||
-- /42/ ==> Nothing
|
||||
|
||||
parsePath (s "search" </> string) location
|
||||
-- /search/cats/ ==> Just "cats"
|
||||
-- /search/frog ==> Just "frog"
|
||||
-- /search/ ==> Nothing
|
||||
-- /cats/ ==> Nothing
|
||||
-}
|
||||
(</>) : Parser a b -> Parser b c -> Parser a c
|
||||
(</>) (Parser parseBefore) (Parser parseAfter) =
|
||||
Parser <| \state ->
|
||||
List.concatMap parseAfter (parseBefore state)
|
||||
|
||||
|
||||
infixr 7 </>
|
||||
|
||||
|
||||
{-| Transform a path parser.
|
||||
|
||||
type alias Comment = { author : String, id : Int }
|
||||
|
||||
rawComment : Parser (String -> Int -> a) a
|
||||
rawComment =
|
||||
s "user" </> string </> s "comments" </> int
|
||||
|
||||
comment : Parser (Comment -> a) a
|
||||
comment =
|
||||
map Comment rawComment
|
||||
|
||||
parsePath comment location
|
||||
-- /user/bob/comments/42 ==> Just { author = "bob", id = 42 }
|
||||
-- /user/tom/comments/35 ==> Just { author = "tom", id = 35 }
|
||||
-- /user/sam/ ==> Nothing
|
||||
-}
|
||||
map : a -> Parser a b -> Parser (b -> c) c
|
||||
map subValue (Parser parse) =
|
||||
Parser <| \{ visited, unvisited, params, value } ->
|
||||
List.map (mapHelp value) <| parse <|
|
||||
{ visited = visited
|
||||
, unvisited = unvisited
|
||||
, params = params
|
||||
, value = subValue
|
||||
}
|
||||
|
||||
|
||||
mapHelp : (a -> b) -> State a -> State b
|
||||
mapHelp func {visited, unvisited, params, value} =
|
||||
{ visited = visited
|
||||
, unvisited = unvisited
|
||||
, params = params
|
||||
, value = func value
|
||||
}
|
||||
|
||||
|
||||
{-| Try a bunch of different path parsers.
|
||||
|
||||
type Route
|
||||
= Search String
|
||||
| Blog Int
|
||||
| User String
|
||||
| Comment String Int
|
||||
|
||||
route : Parser (Route -> a) a
|
||||
route =
|
||||
oneOf
|
||||
[ map Search (s "search" </> string)
|
||||
, map Blog (s "blog" </> int)
|
||||
, map User (s "user" </> string)
|
||||
, map Comment (s "user" </> string </> "comments" </> int)
|
||||
]
|
||||
|
||||
parsePath route location
|
||||
-- /search/cats ==> Just (Search "cats")
|
||||
-- /search/ ==> Nothing
|
||||
|
||||
-- /blog/42 ==> Just (Blog 42)
|
||||
-- /blog/cats ==> Nothing
|
||||
|
||||
-- /user/sam/ ==> Just (User "sam")
|
||||
-- /user/bob/comments/42 ==> Just (Comment "bob" 42)
|
||||
-- /user/tom/comments/35 ==> Just (Comment "tom" 35)
|
||||
-- /user/ ==> Nothing
|
||||
|
||||
-}
|
||||
oneOf : List (Parser a b) -> Parser a b
|
||||
oneOf parsers =
|
||||
Parser <| \state ->
|
||||
List.concatMap (\(Parser parser) -> parser state) parsers
|
||||
|
||||
|
||||
{-| A parser that does not consume any path segments.
|
||||
|
||||
type BlogRoute = Overview | Post Int
|
||||
|
||||
blogRoute : Parser (BlogRoute -> a) a
|
||||
blogRoute =
|
||||
oneOf
|
||||
[ map Overview top
|
||||
, map Post (s "post" </> int)
|
||||
]
|
||||
|
||||
parsePath (s "blog" </> blogRoute) location
|
||||
-- /blog/ ==> Just Overview
|
||||
-- /blog/post/42 ==> Just (Post 42)
|
||||
-}
|
||||
top : Parser a a
|
||||
top =
|
||||
Parser <| \state -> [state]
|
||||
|
||||
|
||||
|
||||
-- QUERY PARAMETERS
|
||||
|
||||
|
||||
{-| Turn query parameters like `?name=tom&age=42` into nice Elm data.
|
||||
-}
|
||||
type QueryParser a b =
|
||||
QueryParser (State a -> List (State b))
|
||||
|
||||
|
||||
{-| Parse some query parameters.
|
||||
|
||||
type Route = BlogList (Maybe String) | BlogPost Int
|
||||
|
||||
route : Parser (Route -> a) a
|
||||
route =
|
||||
oneOf
|
||||
[ map BlogList (s "blog" <?> stringParam "search")
|
||||
, map BlogPost (s "blog" </> int)
|
||||
]
|
||||
|
||||
parsePath route location
|
||||
-- /blog/ ==> Just (BlogList Nothing)
|
||||
-- /blog/?search=cats ==> Just (BlogList (Just "cats"))
|
||||
-- /blog/42 ==> Just (BlogPost 42)
|
||||
-}
|
||||
(<?>) : Parser a b -> QueryParser b c -> Parser a c
|
||||
(<?>) (Parser parser) (QueryParser queryParser) =
|
||||
Parser <| \state ->
|
||||
List.concatMap queryParser (parser state)
|
||||
|
||||
|
||||
infixl 8 <?>
|
||||
|
||||
|
||||
{-| Parse a query parameter as a `String`.
|
||||
|
||||
parsePath (s "blog" <?> stringParam "search") location
|
||||
-- /blog/ ==> Just (Overview Nothing)
|
||||
-- /blog/?search=cats ==> Just (Overview (Just "cats"))
|
||||
-}
|
||||
stringParam : String -> QueryParser (Maybe String -> a) a
|
||||
stringParam name =
|
||||
customParam name identity
|
||||
|
||||
|
||||
{-| Parse a query parameter as an `Int`. Maybe you want to show paginated
|
||||
search results. You could have a `start` query parameter to say which result
|
||||
should appear first.
|
||||
|
||||
parsePath (s "results" <?> intParam "start") location
|
||||
-- /results ==> Just Nothing
|
||||
-- /results?start=10 ==> Just (Just 10)
|
||||
-}
|
||||
intParam : String -> QueryParser (Maybe Int -> a) a
|
||||
intParam name =
|
||||
customParam name intParamHelp
|
||||
|
||||
|
||||
intParamHelp : Maybe String -> Maybe Int
|
||||
intParamHelp maybeValue =
|
||||
case maybeValue of
|
||||
Nothing ->
|
||||
Nothing
|
||||
|
||||
Just value ->
|
||||
Result.toMaybe (String.toInt value)
|
||||
|
||||
|
||||
{-| Create a custom query parser. You could create parsers like these:
|
||||
|
||||
jsonParam : String -> Decoder a -> QueryParser (Maybe a -> b) b
|
||||
enumParam : String -> Dict String a -> QueryParser (Maybe a -> b) b
|
||||
|
||||
It may be worthwhile to have these in this library directly. If you need
|
||||
either one in practice, please open an issue [here][] describing your exact
|
||||
scenario. We can use that data to decide if they should be added.
|
||||
|
||||
[here]: https://github.com/evancz/url-parser/issues
|
||||
-}
|
||||
customParam : String -> (Maybe String -> a) -> QueryParser (a -> b) b
|
||||
customParam key func =
|
||||
QueryParser <| \{ visited, unvisited, params, value } ->
|
||||
[ State visited unvisited params (value (func (Dict.get key params))) ]
|
||||
|
||||
|
||||
|
||||
-- RUN A PARSER
|
||||
|
||||
|
||||
{-| Parse based on `location.pathname` and `location.search`. This parser
|
||||
ignores the hash entirely.
|
||||
-}
|
||||
parsePath : Parser (a -> a) a -> Navigation.Location -> Maybe a
|
||||
parsePath parser location =
|
||||
parse parser location.pathname (parseParams location.search)
|
||||
|
||||
|
||||
{-| Parse based on `location.hash` and `location.search`. This parser
|
||||
ignores the normal path entirely.
|
||||
-}
|
||||
parseHash : Parser (a -> a) a -> Navigation.Location -> Maybe a
|
||||
parseHash parser location =
|
||||
parse parser (String.dropLeft 1 location.hash) (parseParams location.search)
|
||||
|
||||
|
||||
|
||||
-- PARSER HELPERS
|
||||
|
||||
|
||||
parse : Parser (a -> a) a -> String -> Dict String String -> Maybe a
|
||||
parse (Parser parser) url params =
|
||||
parseHelp <| parser <|
|
||||
{ visited = []
|
||||
, unvisited = splitUrl url
|
||||
, params = params
|
||||
, value = identity
|
||||
}
|
||||
|
||||
|
||||
parseHelp : List (State a) -> Maybe a
|
||||
parseHelp states =
|
||||
case states of
|
||||
[] ->
|
||||
Nothing
|
||||
|
||||
state :: rest ->
|
||||
case state.unvisited of
|
||||
[] ->
|
||||
Just state.value
|
||||
|
||||
[""] ->
|
||||
Just state.value
|
||||
|
||||
_ ->
|
||||
parseHelp rest
|
||||
|
||||
|
||||
splitUrl : String -> List String
|
||||
splitUrl url =
|
||||
case String.split "/" url of
|
||||
"" :: segments ->
|
||||
segments
|
||||
|
||||
segments ->
|
||||
segments
|
||||
|
||||
|
||||
parseParams : String -> Dict String String
|
||||
parseParams queryString =
|
||||
queryString
|
||||
|> String.dropLeft 1
|
||||
|> String.split "&"
|
||||
|> List.filterMap toKeyValuePair
|
||||
|> Dict.fromList
|
||||
|
||||
|
||||
toKeyValuePair : String -> Maybe (String, String)
|
||||
toKeyValuePair segment =
|
||||
case String.split "=" segment of
|
||||
[key, value] ->
|
||||
Maybe.map2 (,) (Http.decodeUri key) (Http.decodeUri value)
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
Reference in New Issue
Block a user