Add part5

This commit is contained in:
Richard Feldman
2018-04-28 16:55:52 -04:00
parent d4718c64b4
commit b0f8f8ee42
576 changed files with 97325 additions and 0 deletions

View File

@@ -0,0 +1 @@
elm-stuff

View File

@@ -0,0 +1,30 @@
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 Evan Czaplicki nor the names of other
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
OWNER 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.

View File

@@ -0,0 +1,28 @@
# Navigation
Normally when the address bar changes, the browser sends some HTTP requests to load new pages.
This library lets you capture navigation and handle it yourself. No need to kick off a request to your servers.
## Examples
Check out the `examples/` directory of this repo. The `README` there will give you more information.
## Right and Middle Clicks on Hashless URLs
We got an issue asking "[what is the best way to handle clicks on *normal* URLs?](https://github.com/elm-lang/navigation/issues/13)" where you want to handle the navigation by hand, but also permit middle and right clicks.
The pending solution lives [here](https://github.com/elm-lang/html/issues/110).
## Context
You want your website to load quickly, especially if many users will be on mobile phones. You also want to send as little data as possible to users, especially if they have slow internet connections or data caps.
> For some reason, this general goal is called “Single Page Apps” or SPAs in the JavaScript world. It is odd in that the essence is that you want to manage multiple pages intelligently, and maybe “asset management” would have been clearer, but that ship has sailed.
One important trick is to use the browser cache as much as possible. Ideally, when a user navigates to a new page, they do not make *any* HTTP requests. They have it all already. In a good case, you have most of the JS code you need already, and you just ask for a tiny bit more.
Normally, browser navigation causes an HTTP request for some HTML. That HTML may then fetch some JavaScript and images and other stuff. By capturing navigation events (like this library does) you can skip that first HTTP request and figure out a way to get only the assets you are missing.

View File

@@ -0,0 +1,19 @@
{
"version": "2.1.0",
"summary": "Manage browser navigation yourself (a.k.a. SPA routing, browser history)",
"repository": "http://github.com/elm-lang/navigation.git",
"license": "BSD3",
"source-directories": [
"src"
],
"exposed-modules": [
"Navigation"
],
"native-modules": true,
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/dom": "1.1.1 <= v < 2.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,78 @@
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Navigation
main =
Navigation.program UrlChange
{ init = init
, view = view
, update = update
, subscriptions = (\_ -> Sub.none)
}
-- MODEL
type alias Model =
{ history : List Navigation.Location
}
init : Navigation.Location -> ( Model, Cmd Msg )
init location =
( Model [ location ]
, Cmd.none
)
-- UPDATE
type Msg
= UrlChange Navigation.Location
{- We are just storing the location in our history in this example, but
normally, you would use a package like evancz/url-parser to parse the path
or hash into nicely structured Elm values.
<http://package.elm-lang.org/packages/evancz/url-parser/latest>
-}
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
UrlChange location ->
( { model | history = location :: model.history }
, Cmd.none
)
-- VIEW
view : Model -> Html msg
view model =
div []
[ h1 [] [ text "Pages" ]
, ul [] (List.map viewLink [ "bears", "cats", "dogs", "elephants", "fish" ])
, h1 [] [ text "History" ]
, ul [] (List.map viewLocation model.history)
]
viewLink : String -> Html msg
viewLink name =
li [] [ a [ href ("#" ++ name) ] [ text name ] ]
viewLocation : Navigation.Location -> Html msg
viewLocation location =
li [] [ text (location.pathname ++ location.hash) ]

View 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/elm-lang/navigation.git
cd navigation
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.

View File

@@ -0,0 +1,18 @@
{
"version": "1.0.0",
"summary": "Examples of using the elm-lang/navigation library",
"repository": "http://github.com/user/project.git",
"license": "BSD3",
"source-directories": [
"src"
],
"exposed-modules": [
"Navigation"
],
"dependencies": {
"elm-lang/core": "5.0.0 <= v < 6.0.0",
"elm-lang/html": "2.0.0 <= v < 3.0.0",
"elm-lang/navigation": "2.0.0 <= v < 3.0.0"
},
"elm-version": "0.18.0 <= v < 0.19.0"
}

View File

@@ -0,0 +1,107 @@
var _elm_lang$navigation$Native_Navigation = function() {
// FAKE NAVIGATION
function go(n)
{
return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback)
{
if (n !== 0)
{
history.go(n);
}
callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0));
});
}
function pushState(url)
{
return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback)
{
history.pushState({}, '', url);
callback(_elm_lang$core$Native_Scheduler.succeed(getLocation()));
});
}
function replaceState(url)
{
return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback)
{
history.replaceState({}, '', url);
callback(_elm_lang$core$Native_Scheduler.succeed(getLocation()));
});
}
// REAL NAVIGATION
function reloadPage(skipCache)
{
return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback)
{
document.location.reload(skipCache);
callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0));
});
}
function setLocation(url)
{
return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback)
{
try
{
window.location = url;
}
catch(err)
{
// Only Firefox can throw a NS_ERROR_MALFORMED_URI exception here.
// Other browsers reload the page, so let's be consistent about that.
document.location.reload(false);
}
callback(_elm_lang$core$Native_Scheduler.succeed(_elm_lang$core$Native_Utils.Tuple0));
});
}
// GET LOCATION
function getLocation()
{
var location = document.location;
return {
href: location.href,
host: location.host,
hostname: location.hostname,
protocol: location.protocol,
origin: location.origin,
port_: location.port,
pathname: location.pathname,
search: location.search,
hash: location.hash,
username: location.username,
password: location.password
};
}
// DETECT IE11 PROBLEMS
function isInternetExplorer11()
{
return window.navigator.userAgent.indexOf('Trident') !== -1;
}
return {
go: go,
setLocation: setLocation,
reloadPage: reloadPage,
pushState: pushState,
replaceState: replaceState,
getLocation: getLocation,
isInternetExplorer11: isInternetExplorer11
};
}();

View File

@@ -0,0 +1,424 @@
effect module Navigation where { command = MyCmd, subscription = MySub } exposing
( back, forward
, load, reload, reloadAndSkipCache
, newUrl, modifyUrl
, program, programWithFlags
, Location
)
{-| This is a library for managing browser navigation yourself.
The core functionality is the ability to &ldquo;navigate&rdquo; to new URLs,
changing the address bar of the browser *without* the browser kicking off a
request to your servers. Instead, you manage the changes yourself in Elm.
# Change the URL
@docs newUrl, modifyUrl
# Navigation
@docs back, forward
# Force Page Loads
@docs load, reload, reloadAndSkipCache
# Programs with Locations
@docs program, programWithFlags, Location
-}
import Dom.LowLevel exposing (onWindow)
import Html exposing (Html)
import Json.Decode as Json
import Native.Navigation
import Process
import Task exposing (Task)
-- PROGRAMS
{-| Same as [`Html.program`][doc], but your `update` function gets messages
whenever the URL changes.
[doc]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html#program
The first difference is the `Location -> msg` argument. This converts a
[`Location`](#location) into a message whenever the URL changes. That message
is fed into your `update` function just like any other one.
The second difference is that the `init` function takes `Location` as an
argument. This lets you use the URL on the first frame.
**Note:** A location message is produced every time the URL changes. This
includes things exposed by this library, like `back` and `newUrl`, as well as
whenever the user clicks the back or forward buttons of the browsers. So if
the URL changes, you will hear about it in your `update` function.
-}
program
: (Location -> msg)
->
{ init : Location -> (model, Cmd msg)
, update : msg -> model -> (model, Cmd msg)
, view : model -> Html msg
, subscriptions : model -> Sub msg
}
-> Program Never model msg
program locationToMessage stuff =
let
subs model =
Sub.batch
[ subscription (Monitor locationToMessage)
, stuff.subscriptions model
]
init =
stuff.init (Native.Navigation.getLocation ())
in
Html.program
{ init = init
, view = stuff.view
, update = stuff.update
, subscriptions = subs
}
{-| Works the same as [`program`](#program), but it can also handle flags.
See [`Html.programWithFlags`][doc] for more information.
[doc]: http://package.elm-lang.org/packages/elm-lang/html/latest/Html#programWithFlags
-}
programWithFlags
: (Location -> msg)
->
{ init : flags -> Location -> (model, Cmd msg)
, update : msg -> model -> (model, Cmd msg)
, view : model -> Html msg
, subscriptions : model -> Sub msg
}
-> Program flags model msg
programWithFlags locationToMessage stuff =
let
subs model =
Sub.batch
[ subscription (Monitor locationToMessage)
, stuff.subscriptions model
]
init flags =
stuff.init flags (Native.Navigation.getLocation ())
in
Html.programWithFlags
{ init = init
, view = stuff.view
, update = stuff.update
, subscriptions = subs
}
-- TIME TRAVEL
{-| Go back some number of pages. So `back 1` goes back one page, and `back 2`
goes back two pages.
**Note:** You only manage the browser history that *you* created. Think of this
library as letting you have access to a small part of the overall history. So
if you go back farther than the history you own, you will just go back to some
other website!
-}
back : Int -> Cmd msg
back n =
command (Jump -n)
{-| Go forward some number of pages. So `forward 1` goes forward one page, and
`forward 2` goes forward two pages. If there are no more pages in the future,
this will do nothing.
**Note:** You only manage the browser history that *you* created. Think of this
library as letting you have access to a small part of the overall history. So
if you go forward farther than the history you own, the user will end up on
whatever website they visited next!
-}
forward : Int -> Cmd msg
forward n =
command (Jump n)
{-| Leave the current page and load the given URL. **This always results in a
page load**, even if the provided URL is the same as the current one.
load "http://elm-lang.org"
Use [`newUrl`](#newUrl) and [`modifyUrl`](#modifyUrl) if you want to change
the URL without a page load.
-}
load : String -> Cmd msg
load url =
command (Visit url)
{-| Reload the current page. **This always results in a page load!**
This may grab resources from the browser cache, so use
[`reloadAndSkipCache`](reloadAndSkipCache) if you want to be sure
that you are not loading any cached resources.
-}
reload : Cmd msg
reload =
command (Reload False)
{-| Reload the current page without using the browser cache. **This always
results in a page load!** It is more common to want [`reload`](reload).
-}
reloadAndSkipCache : Cmd msg
reloadAndSkipCache =
command (Reload True)
-- CHANGE HISTORY
{-| Step to a new URL. This will add a new entry to the browser history.
**Note:** If the user has gone `back` a few pages, there will be &ldquo;future
pages&rdquo; that the user can go `forward` to. Adding a new URL in that
scenario will clear out any future pages. It is like going back in time and
making a different choice.
-}
newUrl : String -> Cmd msg
newUrl url =
command (New url)
{-| Modify the current URL. This *will not* add a new entry to the browser
history. It just changes the one you are on right now.
-}
modifyUrl : String -> Cmd msg
modifyUrl url =
command (Modify url)
-- LOCATION
{-| A bunch of information about the address bar.
**Note 1:** Almost everyone will want to use a URL parsing library like
[`evancz/url-parser`][parse] to turn a `Location` into something more useful
in your `update` function.
[parse]: https://github.com/evancz/url-parser
**Note 2:** These fields correspond exactly with the fields of `document.location`
as described [here](https://developer.mozilla.org/en-US/docs/Web/API/Location).
-}
type alias Location =
{ href : String
, host : String
, hostname : String
, protocol : String
, origin : String
, port_ : String
, pathname : String
, search : String
, hash : String
, username : String
, password : String
}
-- EFFECT MANAGER
type MyCmd msg
= Jump Int
| New String
| Modify String
| Visit String
| Reload Bool
cmdMap : (a -> b) -> MyCmd a -> MyCmd b
cmdMap _ myCmd =
case myCmd of
Jump n ->
Jump n
New url ->
New url
Modify url ->
Modify url
Visit url ->
Visit url
Reload skipCache ->
Reload skipCache
type MySub msg =
Monitor (Location -> msg)
subMap : (a -> b) -> MySub a -> MySub b
subMap func (Monitor tagger) =
Monitor (tagger >> func)
-- STATE
type alias State msg =
{ subs : List (MySub msg)
, popWatcher : Maybe PopWatcher
}
type PopWatcher
= Normal Process.Id
| InternetExplorer Process.Id Process.Id
-- INIT
init : Task Never (State msg)
init =
Task.succeed (State [] Nothing)
-- SELF MESSAGES
onSelfMsg : Platform.Router msg Location -> Location -> State msg -> Task Never (State msg)
onSelfMsg router location state =
notify router state.subs location
&> Task.succeed state
(&>) task1 task2 =
Task.andThen (\_ -> task2) task1
-- APP MESSAGES
onEffects : Platform.Router msg Location -> List (MyCmd msg) -> List (MySub msg) -> State msg -> Task Never (State msg)
onEffects router cmds subs {popWatcher} =
let
stepState =
case (subs, popWatcher) of
([], Just watcher) ->
killPopWatcher watcher
&> Task.succeed (State subs Nothing)
(_ :: _, Nothing) ->
Task.map (State subs << Just) (spawnPopWatcher router)
(_, _) ->
Task.succeed (State subs popWatcher)
in
Task.sequence (List.map (cmdHelp router subs) cmds)
&> stepState
cmdHelp : Platform.Router msg Location -> List (MySub msg) -> MyCmd msg -> Task Never ()
cmdHelp router subs cmd =
case cmd of
Jump n ->
go n
New url ->
pushState url
|> Task.andThen (notify router subs)
Modify url ->
replaceState url
|> Task.andThen (notify router subs)
Visit url ->
setLocation url
Reload skipCache ->
reloadPage skipCache
notify : Platform.Router msg Location -> List (MySub msg) -> Location -> Task x ()
notify router subs location =
let
send (Monitor tagger) =
Platform.sendToApp router (tagger location)
in
Task.sequence (List.map send subs)
&> Task.succeed ()
setLocation : String -> Task x ()
setLocation =
Native.Navigation.setLocation
reloadPage : Bool -> Task x ()
reloadPage =
Native.Navigation.reloadPage
go : Int -> Task x ()
go =
Native.Navigation.go
pushState : String -> Task x Location
pushState =
Native.Navigation.pushState
replaceState : String -> Task x Location
replaceState =
Native.Navigation.replaceState
-- POP WATCHER STUFF
spawnPopWatcher : Platform.Router msg Location -> Task x PopWatcher
spawnPopWatcher router =
let
reportLocation _ =
Platform.sendToSelf router (Native.Navigation.getLocation ())
in
if Native.Navigation.isInternetExplorer11 () then
Task.map2 InternetExplorer
(Process.spawn (onWindow "popstate" Json.value reportLocation))
(Process.spawn (onWindow "hashchange" Json.value reportLocation))
else
Task.map Normal <|
Process.spawn (onWindow "popstate" Json.value reportLocation)
killPopWatcher : PopWatcher -> Task x ()
killPopWatcher popWatcher =
case popWatcher of
Normal pid ->
Process.kill pid
InternetExplorer pid1 pid2 ->
Process.kill pid1
&> Process.kill pid2