1. OverviewManipulating browser history| 00:00 | The HTML5 session history API is a
small set of objects and methods for
| | 00:05 | manipulating the history stack in a browser.
| | 00:08 | With this API you may add items to the
browser history and change the location
| | 00:12 | URL without initiating a new
connection to the web server.
| | 00:16 | This has great value for AJAX and other
applications that may want to update a
| | 00:21 | page without causing a complete page
reload, while still providing bookmarkable
| | 00:26 | URLs for your users.
| | 00:28 | Officially, the spec is called the
HTML5 session history and navigation API.
| | 00:34 | It's a simple spec, and it's fairly stable.
| | 00:37 | The implementations are a little
inconsistent, but it's not difficult to manage.
| | 00:42 | The HTML5 session history API
requires a network connection;
| | 00:46 | it will not work on a local file on your system.
| | 00:49 | The reason for this is that it
requires a host name, and it requires that the
| | 00:54 | host name not be changed in any of the
URLs that are pushed onto the stack, as
| | 00:58 | this would be considered a security risk.
| | 01:00 | So in order to follow along with the
exercise files in this course, or even to
| | 01:05 | work with the HTML5 session history
API at all, you will need a web server.
| | 01:11 | You cannot use this API with
a file on your local system.
| | 01:15 | If you don't have a web server, or you
would like to work on a local machine,
| | 01:19 | take a look at the course
Installing Apache, MySQL, and PHP here in the
| | 01:24 | lynda.com Online Training Library.
| | 01:27 | The HTML5 session history API allows
new items to be pushed onto the history
| | 01:31 | stack, or the top of the stack maybe modified.
| | 01:35 | When the Back button or Forward button
is pressed, or the history.go method is
| | 01:40 | called, an event is triggered and that
event maybe captured to do local page
| | 01:45 | updates without having
to go back to the network.
| | 01:47 | This provides significant
opportunities for performance improvements.
| | 01:52 | The API works in Chrome, Safari,
Firefox, and most mobile browsers.
| | 01:57 | Support is planned for upcoming
versions of Opera, and it is not supported in
| | 02:01 | current versions of Microsoft Internet Explorer.
| | 02:05 | The HTML5 session history API
provides a simple and usable interface for
| | 02:11 | manipulating and reading
the browser history stack.
| | Collapse this transcript |
| Viewing a sample application| 00:00 | To demonstrate the HTML5 session
history API, I've created a simple photo
| | 00:05 | browser application.
| | 00:06 | This is a simple implementation of
a very common use of this feature.
| | 00:11 | Let's take a look at how this works.
| | 00:13 | I am using the Chrome web
browser for most of the course.
| | 00:16 | Of all the browsers that support the
HTML5 session history API, Chrome is
| | 00:21 | the most consistent.
| | 00:22 | This application works fine in other
browsers as well, as we'll see later in this movie.
| | 00:27 | Unfortunately, Internet Explorer does not
support the HTML5 session history API at all.
| | 00:33 | You will also notice that
this is running on my server.
| | 00:37 | You will notice in the location
bar at the top it says h5.bw.org.
| | 00:42 | That's a temporary server that I've
set up just for recording this course.
| | 00:46 | Please do not try to run
your lesson files on my server;
| | 00:49 | that will not work.
| | 00:50 | You will need your own
server to run the lesson files.
| | 00:53 | We'll look at the code in a lot
more detail in the next chapter,
| | 00:57 | but for now, let's just take a
quick tour of how this works.
| | 01:00 | You will notice that in the location bar,
a file name part is Pager-Coffee.html,
| | 01:07 | And so this is a photo browser--
| | 01:08 | I am calling it also an Image Pager--
and you will notice that it is showing a cup
| | 01:13 | of coffee and it has the
caption that says Coffee.
| | 01:16 | If I press the Left button here, you
will see that it changes to Scissors and
| | 01:22 | you will see also that the URL changes
to say Pager-Scissors.html, the title
| | 01:27 | bar changes up here, and yet, it's not going back
out to the network to load another page.
| | 01:33 | It's just changing the image here.
| | 01:35 | If I press it again, we get
another picture, this one a Paper.
| | 01:38 | You see this message here, it says,
"pushing Paper onto browser history," and I
| | 01:43 | press it again, now it says,
"pushing Rock onto browser history."
| | 01:47 | If I press the Back button, we get
back to the Paper which was the last one;
| | 01:51 | press it again, we get back to the Scissors.
| | 01:54 | You will notice, if I press the
Forward button and hold it, we have
| | 01:58 | several of them in here.
| | 01:59 | I can skip forward to Paper, I can
skip backwards to Coffee, and all of that
| | 02:04 | happens and it changes the URL, but it
does not go back out to the network to
| | 02:08 | load the page again.
| | 02:09 | We can see that this also works in
other browsers. Here is Firefox. And we can
| | 02:15 | go forward this time. We have Keyboard,
we have a mouse. We'll go backward a few.
| | 02:21 | It takes it a moment the first time
it loads an image, but then it doesn't
| | 02:24 | anymore, and you see that all the other
information is updating as well. And if we
| | 02:28 | hold the Back button here, we've got
Coffee, hold the Forward button here, we've
| | 02:32 | got Scissors, and all of that
works exactly as we expected.
| | 02:36 | It also works just fine in Safari.
| | 02:39 | This is Safari here. And here's our Back button.
| | 02:47 | We've got Coffee, we have Paper,
Forward, Keyboard, and Mouse, and all of
| | 02:53 | that works fine in Safari.
| | 02:55 | If we load up Internet Explorer, we see
we have this little alert box, it says,
| | 02:59 | "This browser does not support
HTML5 Browser History Manipulation."
| | 03:03 | If I say OK, it goes ahead and loads
the image, and it works just fine, but it
| | 03:09 | does not update the URL, and it does
not update the browser history, because it
| | 03:15 | simply doesn't support that API.
| | 03:16 | So I have a test in the code that tests
whether or not the browser supports the
| | 03:20 | spec and if it doesn't, then it just
doesn't use those features, but it goes
| | 03:25 | ahead and degrades gracefully.
| | 03:28 | So a photo browser is a common use of
the HTML5 session history API because
| | 03:33 | it presents a common problem where an
entire page maybe loaded just to update one item.
| | 03:38 | Here we can see how this use case can
be significantly improved by using the
| | 03:43 | HTML5 session history API.
| | 03:45 | In the rest of this course, we will
look at the details of how this is
| | 03:48 | implemented, so that you can
understand how to create an application like
| | 03:51 | this yourself.
| | Collapse this transcript |
|
|
2. The DetailsDetecting HTML5 History API support| 00:00 | Detecting support for the HTML5
session history API is relatively simple.
| | 00:05 | All we have to do is test for the
presence of a couple of object methods.
| | 00:10 | Here on the screen, I have got
opened in my editor the 01-detecting.html
| | 00:16 | file, and you will notice here the
JavaScript is very simple and the HTML is very simple,
| | 00:23 | so that's the HTML at the bottom of the file.
| | 00:27 | Here in the JavaScript, all we are
doing is on window.onload, which is the way
| | 00:32 | that I like to load JavaScript,
the window.onload event happens after
| | 00:36 | everything is loaded in the browser,
and only then will it call the JavaScript
| | 00:41 | if I do it this way.
| | 00:43 | So it calls init, and then init calls
this isSupportedBrowserHistory and has
| | 00:50 | historySupported variable that gets set,
and so that variable is declared at
| | 00:54 | the top of the file, so that's a
global variable. And then it calls this
| | 00:57 | function isSupportedBrowserHistory and that
checks for window.history and history.pushState.
| | 01:05 | If both objects exist then history is
considered to be supported, and we test if
| | 01:11 | history is supported, we get "This
browser supports the HTML5 browser history API"
| | 01:16 | in the statusMessage, and if it's not,
we get this other message, "This browser
| | 01:20 | does not support the HTML5 browser history API."
| | 01:24 | So let's go ahead and try this
in Google Chrome, and I'll click on
| | 01:29 | 01-detecting.html and we see "This
browser supports the HTML5 browser history API."
| | 01:37 | If I try the same thing in Internet
Explorer--and I am going to click on that
| | 01:41 | same link 01-detecting--you see it
says, "This browser does not support the
| | 01:46 | HTML5 browser history API."
| | 01:49 | So this is how we test for the
existence of the API in our browser.
| | 01:55 | It's a simple test for these two
objects, and you can see that's a
| | 02:00 | relatively simple operation.
| | 02:02 | Once we know that the browser
supports the API, we can begin using it.
| | Collapse this transcript |
| Pushing a new URL onto the stack| 00:00 | The first thing we want to do with the
HTML5 session history API is to push a
| | 00:04 | new value onto the history stack.
| | 00:08 | So what I have here is a working
copy of 02-pushstate-start.html.
| | 00:15 | I made a working copy of that, and I
called it 02-pushstate-working.html.
| | 00:20 | I am actually editing directly on the server.
| | 00:23 | There is a feature here in Notepad++
that allows me to do that over SSH.
| | 00:28 | I know on the Mac you can do the same
thing with BBEdit, and I believe you can
| | 00:32 | also do it with BBEdit's free version,
which is called TextWrangler. And in any
| | 00:37 | event, this is the file and I am
editing it directly on the server.
| | 00:41 | Notice that it's very simple and very short.
| | 00:43 | This is just our starting place.
| | 00:45 | You see the JavaScript is just a few
lines, and the HTML is very, very simple.
| | 00:55 | So let's go ahead and
fire this up in the browser.
| | 00:57 | This is actually the place where
we left off in our last example.
| | 01:01 | So if I click on pushstate-working--this is
the one that I have got opened in my editor--
| | 01:05 | you see it just says, "This browser
supports the HTML5 browser history API."
| | 01:09 | I will go back to the editor, and I am
just going to push a bunch of values
| | 01:16 | onto the history stack here.
| | 01:19 | So right after the statusMessage, I am
just going to type in a little for loop.
| | 01:22 | So I am calling the
history.pushState method that we tested for in the
| | 01:33 | isSupportedBrowserHistory.
| | 01:35 | The first argument is a state object.
| | 01:38 | It can be any valid JavaScript object.
| | 01:40 | I am just going to give
it this index number here.
| | 01:43 | This for loop will loop from 0 to 9 and so it
will push 10 objects onto the history stack.
| | 01:51 | Each of these objects will have the
state object, which in this case is just that
| | 01:55 | integer variable, and the
next argument is a description.
| | 02:01 | This is supposed to be what
shows up in the browser history.
| | 02:03 | It's not consistently implemented on all
browsers, and so we'll see how this works.
| | 02:08 | I am just going to say here i is i,
value of i there, and the last item is
| | 02:21 | actually the URL that will go in the history.
| | 02:24 | In this case, I am just going to put in a
slash and the number and .html and that's it.
| | 02:35 | Go ahead and save that,
and we will run it in the browser.
| | 02:39 | Now, you notice what was here when we
pushed this back, we just have a lot of
| | 02:42 | other stuff in the history. We don't
have the things we are pushing now.
| | 02:46 | When I reload this, you notice
that now up here it says 9.html.
| | 02:51 | It actually pushed each of those onto
the stack, and it shows them up there, and
| | 02:55 | you will notice that I have Browser History Demo.
| | 02:57 | It did not use the string that we put
in there. We'll learn later how to make
| | 03:01 | that work across browsers.
| | 03:02 | But when I press this Back button, you
see it says 8.html, 7.html, 6.html like
| | 03:08 | that, and as I go forward, it
steps through them forward like that.
| | 03:12 | We put 10 items on the stack there,
0 through 9, and we've now manipulated
| | 03:18 | our browser history.
| | 03:19 | So that's a pretty easy thing to do, isn't it?
| | 03:22 | Basically, that one line of code,
history.pushState, allows you to put whatever you
| | 03:27 | want to on that history stack.
| | 03:30 | So pushing an object onto the history
stack is really a very simple operation
| | 03:34 | using the HTML5 session history API.
| | 03:37 | It's also very easy to retrieve
these items once they're there,
| | 03:41 | so we'll look at how to
do that in the next movie.
| | Collapse this transcript |
| Handling back and forward buttons with the popstate event| 00:00 | When a user presses the Back or
Forward button on the browser, or when
| | 00:04 | history.go is called in a JavaScript
application, the popstate event is fired.
| | 00:09 | It's relatively simple to
implement a handler for this event.
| | 00:13 | Here we have 03-popstate-working.html,
which is a working copy of
| | 00:18 | 03-popstate-start.html.
I'm editing this on the server, so we can edit it
| | 00:26 | and test it in our browser.
| | 00:28 | You'll notice that it's very simple.
| | 00:30 | This is really just where we
left off from our last lesson.
| | 00:35 | So here, you see in the init method
we are pushing 10 items onto the history
| | 00:40 | stack, and now we want be able to step
through those with the Back button and
| | 00:45 | get the value from them.
| | 00:47 | So if you remember, the first argument to
this pushState method is a state object.
| | 00:54 | This state object is what we're
going to read off of the stack.
| | 00:58 | So the state object in this case, it's
just the integer from our loop, so it'll
| | 01:01 | be 0, 1, 2, 3, 4, 5, et cetera, on up to 9.
| | 01:05 | So we're just going to go ahead in
here and we're going to register an
| | 01:11 | EventHandler for the popstate event.
| | 01:20 | So we'll say window.onpopstate =
popStateHandler, and we'll come up here and
| | 01:28 | we'll create a function for that.
| | 01:31 | That gets an event
object. And it's pretty simple.
| | 01:41 | The first thing it does is it tests
to see if the event object has a state
| | 01:45 | attribute, and it simply checks
to see if it does not equal null.
| | 01:57 | Now, in JavaScript it's important to
understand that the null object is a special object.
| | 02:03 | It's not a 0 value, it's not a false
value, it's a special object of type null.
| | 02:10 | And while it will evaluate to
false, so does evaluate to false,
| | 02:15 | so I can't just say if(event.state),
if the value of event.state may be an
| | 02:19 | integer with a value of 0, which
in this case we are actually using.
| | 02:23 | We have to test it for whether or
not that attribute is actually set,
| | 02:28 | and null is how you do that.
| | 02:29 | So we're testing it against null.
| | 02:31 | Now, I'm just going to set a statusMessage.
| | 02:38 | Remember, the statusMessage is a method
in bwH5.js JavaScript, and it just sets
| | 02:45 | a message here in this special
statusMessage paragraph on our page.
| | 02:49 | So I'll just say got event,
and state is event.state.
| | 03:01 | That's all there is to it!
| | 03:03 | I'm going to go ahead and I'm going to
save this, and we'll run it in the browser.
| | 03:06 | Now, go ahead here and click on
popstate-working, and you notice we have
| | 03:12 | the 9.html up here.
| | 03:14 | When I press the Back button,
we'll see "got event, state is: 8."
| | 03:17 | If I press the Forward
button, "got event, state is 9."
| | 03:21 | And as I page through this,
you see that we have our events.
| | 03:29 | That's our EventHandler here being
called, and that event.state has the integer
| | 03:35 | in it because we put that in here
when we did the pushState. That first
| | 03:38 | argument is what gets here.
| | 03:39 | It can be any JavaScript object.
| | 03:41 | I'm just using an integer
here because that's convenient.
| | 03:44 | In fact, I tend to do it this way anyway
in practice because it's really easy to
| | 03:49 | index into an array or to index into
a database with an integer, and it's a
| | 03:53 | small object, it's easy to carry around--
it doesn't present a lot of performance
| | 03:57 | challenges for the browser.
| | 03:59 | It's really, in many, many cases,
it's the right way to do this.
| | 04:03 | There is one more thing I want to show
you about this, and you'll notice when I
| | 04:08 | continue to go back here--and we'll get
back to item 1 and item 0--and when I go
| | 04:13 | back one more, you notice that I get
back to my original state, my original URL,
| | 04:18 | but I don't get a separate state event for that.
| | 04:21 | That's because we didn't put it on the stack.
| | 04:24 | That's not done with pushState, that's
done with replaceState, and that's what
| | 04:28 | we're going to learn about in our next lesson.
| | 04:30 | So reading the value from
popstate, again, is an easy proposition.
| | 04:35 | This is almost enough to build a
complete application using the HTML5 session
| | 04:39 | history API, but we still need to learn
about replaceState, and we're going to do
| | 04:43 | that in our next movie.
| | Collapse this transcript |
| Updating the stack with replaceState()| 00:00 | The HTML5 session history API provides two
different ways to update the browser history:
| | 00:06 | pushState and replaceState.
| | 00:08 | pushState is covered in a previous
movie, and it allows you to push an entry
| | 00:12 | onto the history stack.
| | 00:14 | replaceState is used to update
the current entry on the history stack.
| | 00:18 | So let's take a look at how this works.
| | 00:20 | First, we'll start with a working copy
of 04-replacestate-start.html, and I've
| | 00:27 | called this replacestate-working.html.
| | 00:30 | You'll notice it's substantially the same
as where we left off in our last lesson.
| | 00:36 | But instead of the for loop with 10
different items on the stack, I'm just
| | 00:42 | pushing two different items onto the stack here:
| | 00:44 | number 1 and number 2.
| | 00:47 | I have the popStateHandler to look at
them, and let's just take a look at what
| | 00:50 | this does and what the problem
is that we're going to be fixing.
| | 00:54 | So here's replacestate-working,
and I'll run that in the browser here.
| | 00:58 | You notice it says 2.html. If I press
the Back button, it says 1.html, and we've
| | 01:03 | got an event. The state is 1.
| | 01:05 | If I press the Back button one more
time, you'll notice that there is our
| | 01:08 | original HTML file, but I did not get an event.
| | 01:12 | And because I did not get an event,
my code doesn't actually know that the user
| | 01:17 | pressed the Back button again.
| | 01:19 | There's no new state there.
| | 01:22 | So if I'm like paging through my
images and I want to go back to the first
| | 01:25 | image, I don't actually have a way of
getting there, because there's no state
| | 01:29 | object in this particular event.
| | 01:32 | So let's fix this
problem and see how that works.
| | 01:36 | So I'm going to add a line here before
my first pushState, and it's important
| | 01:40 | that this goes before the first
pushState because once I start pushing states on
| | 01:44 | here, I don't have the top of
the stack available anymore.
| | 01:47 | So I'm going to say history.replaceState.
| | 01:54 | I'm going to give it a number 0,
and I'm going to say the number 0.
| | 01:59 | I'm just going to put a
null here in the last argument.
| | 02:04 | So you remember, the first argument is
the state object; the second argument is
| | 02:09 | a text string that ostensibly is used
in the history, and that works in some
| | 02:14 | browsers and not in other
browsers; and the third one is the URL.
| | 02:18 | Now, because I'm putting a null in the
URL, it knows not to replace the URL.
| | 02:24 | It's there on the stack already.
| | 02:26 | So this is just going to replace
the state object, and the string.
| | 02:30 | So I'm going to go ahead and save
this, and we'll run it in the browser.
| | 02:38 | I'm just going to click on this,
and you notice it goes to 2.html.
| | 02:42 | In many cases, this isn't going to work.
| | 02:44 | Yeah, you see it's actually not working.
It's not doing what you expect,
| | 02:48 | and that's because the existing HTML is cached.
| | 02:51 | So if I just press the Reload button here,
and now we'll find that it actually works.
| | 02:57 | So now we're running the new version,
and you notice it says, "got event," and state
| | 03:01 | is 0, and that's on the original page.
| | 03:04 | So I'm going to reload it one more
time, and you see here it says 2.html.
| | 03:09 | I go back in my history here and I'll
just click this once. I get an event, it
| | 03:13 | says 1, and we have 1.html.
| | 03:16 | I click it again, and now I have my original
page and I got an event and I have a state.
| | 03:21 | What's important about this is that
now I have a way of actually operating on
| | 03:26 | that first item in the stack, even
though the URL is what it originally was and
| | 03:31 | Reload works and does what we expect it to do.
| | 03:34 | Because I'm getting an event,
that means I'm able to put something there and
| | 03:38 | I'm able to control that particular state.
| | 03:41 | That's very important for our application.
| | 03:43 | So you'll see we'll use
this in our final application.
| | 03:48 | So now, we have all the pieces we
need to fully implement the HTML5
| | 03:52 | session history API.
| | 03:54 | In the next movie, we're going to
take a look at a complete application.
| | Collapse this transcript |
| The complete application| 00:00 | This is a complete application
using the HTML5 session history API.
| | 00:05 | It's a simple photo browser, and this
is all implemented in the browser, but of
| | 00:10 | course in practice it could be a
combination of server-side scripting and a
| | 00:15 | database, and you would probably do it
that way for most production applications.
| | 00:19 | This is designed to be a simple
demonstration of this technology and a simple
| | 00:22 | explanation of how it works.
| | 00:24 | And indeed, it's a very simple application.
| | 00:27 | It's only about 90 something lines of
JavaScript, and let's take a look at
| | 00:31 | it real quick here.
| | 00:32 | Here we have the stuff that
goes at the top of the HTML.
| | 00:36 | There is a little bit of CSS here
for formatting of the images and the
| | 00:40 | little paging buttons.
| | 00:43 | We have some data at the top of the JavaScript.
| | 00:46 | These are image URLs and their names.
| | 00:50 | We test for whether or not the API is supported.
| | 00:53 | We have a few utility functions here.
| | 00:55 | Here's our little navigating function,
here is for updating the images, setting
| | 01:01 | the title, our popStateHandler.
| | 01:06 | We have a little trick here so that we
can discern which image is needed from
| | 01:11 | the file name, and we'll get into a
little bit of detail on that in a little bit
| | 01:15 | here, and there is the init.
And finally the HTML is just very, very simple;
| | 01:21 | this is the whole thing right there.
| | 01:24 | So let's look at how it runs in the browser.
| | 01:26 | When it loads up, it loads its initial
image, and what it does is it actually
| | 01:31 | finds the image from the URL.
| | 01:34 | So you notice that the file name is
Pager-Coffee.html. And if we look here at
| | 01:39 | the code and we'll look at the HTML down at
the bottom here, you see our pagerLabel
| | 01:46 | says placeholder, and the
image itself says Placeholder.png.
| | 01:52 | If I go into the browser here--and I
will just navigate up to the Images--
| | 01:57 | and you'll see Placeholder.png is that image
there, and that is not what we're looking at.
| | 02:05 | When you first load this up you will
see the Placeholder loads, and then
| | 02:08 | once the page is loaded, it loads the image
itself, and it puts the word Coffee in here.
| | 02:15 | And where it finds all of that is
right there from the file name, and this is
| | 02:19 | the code that does that.
| | 02:21 | It takes the window location, it
converts it to a string, and it splits it on
| | 02:25 | all of the slashes, and then it pops the last
element off, and that's the file name itself.
| | 02:31 | So that's everything up to the last
slash, and that's just a little trick for
| | 02:35 | how I get that part of it.
| | 02:37 | And now I have just the file name,
and I split the file name on the dot and I
| | 02:43 | take the first element, so that's
everything to the left of the dot, and I
| | 02:46 | split that up on the dash, and I take the last
element there, and that gives me the word Coffee.
| | 02:52 | So it's really just a little trick,
but what this allows me to do is to then go
| | 02:57 | up into my data here and find the
Coffee and the Coffee image and load that up.
| | 03:02 | And the beauty of that is that as I page
through this application and as I click
| | 03:09 | these pager buttons, you will
notice it switches to Pager-Keyboard and
| | 03:13 | Pager-Mouse, and the HTML
can be exactly the same.
| | 03:18 | These files, a Pager-Mouse, Pager-
Coffee, Pager-Rock, all of these files
| | 03:24 | are exactly the same.
| | 03:26 | In fact, on my server it's just one
file and a bunch of symbolic links,
| | 03:31 | and that saves space. It allows you to
update just one file and not have it have to
| | 03:37 | update the same changes in
a number of different files.
| | 03:40 | The reason I did that is so that I could
do this entire application in just HTML.
| | 03:45 | Normally, I would do something like this
with server-side scripting, there would
| | 03:49 | be just one file, and all of the
different URLs would be queries on the one
| | 03:53 | file, with little question mark at
the end and some arguments after it.
| | 03:58 | But I wanted to do this one all in
HTML, just to make it simple for our
| | 04:01 | purposes of learning.
| | 04:03 | So the only complexity was, I needed to
be able to determine which image it was
| | 04:07 | from the file name, and so I've got
this tricky little bit of JavaScript there
| | 04:10 | to do that, and that's
really all that that's for.
| | 04:14 | So you will notice as we click on
these buttons, it says, "pushing Coffee onto
| | 04:19 | browser history," "pushing Scissors onto
browser history," and when I hold the left
| | 04:23 | button here you will notice it says
Page:Coffee, Page:Keyboard, Page:Mouse, like
| | 04:28 | that, and that's
actually the title from up here. This is,
| | 04:32 | in some browsers, this is actually
what's pushed onto the stack, and if we
| | 04:38 | come up here to the navigation
function, this is what gets fired when we
| | 04:43 | click on those buttons.
| | 04:44 | So coming down here to the HTML,
you see onClick="nav(-1)," onClick="nav(1)," so
| | 04:50 | that's for the Back button, passes it a
-1, and the Forward button passes it a
| | 04:54 | plus 1, and so that's our nav function here.
| | 04:58 | And if history is supported, it calls
this makeURI, which just makes the file
| | 05:03 | name, puts a Pager- in front of it and
a .html at the end of it, and then it
| | 05:08 | pushes it onto the history and does
this with window.history.pushState.
| | 05:17 | And so the first argument is the index.
That's just the number that indexes
| | 05:22 | into this array here.
| | 05:23 | So it will be a 0 for Rock,
a 1 for Paper, a 2 for Scissors.
| | 05:27 | And then the string here, which is the
same as what's in the title bar, and this
| | 05:34 | file name, which is your Pager- and
the image name and the .html, and so that
| | 05:40 | gets pushed onto the history.
| | 05:42 | Now, what I discovered, different
browsers will do this in different ways, as far
| | 05:47 | as what strings it puts
in the history list there.
| | 05:51 | Chrome will put whatever's in the
title, and it just grabs the title and it
| | 05:55 | ignores that second argument to pushState.
| | 05:58 | Firefox will only put the title in if
the title has changed; otherwise, it just
| | 06:04 | puts the URL in there.
| | 06:06 | Safari does exactly what
you would expect it to do.
| | 06:10 | It uses that second argument string
from the pushState. And if you look in the
| | 06:14 | spec, it says that the browsers are free to
do this however it is that they want to do it.
| | 06:19 | I would prefer that there is some
standard to it, but there isn't, and so by
| | 06:24 | setting the title each time,
I was able to get this to work right.
| | 06:28 | And so I have a little function here
called setTitle, and every time we navigate
| | 06:34 | we call setTitle, and setTitle is right here.
| | 06:37 | All it does is it sets
document.title to the title that we want.
| | 06:43 | So the rest of this is all very straightforward.
| | 06:46 | We have window.onload. We call init.
init checks to see if the history API is
| | 06:51 | supported, and if not, it puts up a
nice little alert, and we saw that in
| | 06:57 | Internet Explorer in our Overview movie.
| | 07:00 | It registers the popStateHandler,
and here is the popStateHandler right here.
| | 07:05 | It's very, very simple.
| | 07:07 | It checks to see if the event.state is null.
| | 07:10 | It simply copies it to
that global index variable.
| | 07:14 | It puts up a statusMessage saying that
it got the name of the image from the
| | 07:18 | history, and it updates the image
with the index, and it sets the title.
| | 07:23 | It's as simple as that.
| | 07:25 | And all that's getting stored on the
stack is that integer, that index integer.
| | 07:32 | index is a global variable here.
| | 07:34 | It gets set whenever we want to change
things and then it gets used for updating
| | 07:37 | the images in the title and everything else.
| | 07:40 | It's all very, very straightforward.
| | 07:43 | So the first thing we do is we get
the current index from path and again,
| | 07:47 | that's this function here that gets the
path array and finds the file name and
| | 07:50 | decides which element out of the array
it is, and it sets the index with that.
| | 07:56 | It puts up a statusMessage
saying what the initial image is.
| | 07:59 | It checks if the history is supported,
and if not, it does replaceState, and
| | 08:05 | this allows us to use the Back button to
get all the way back to that first one.
| | 08:10 | So if I go all the way back here and
just click on Pager-Coffee--so that's our
| | 08:18 | first one--and if I'll just page
forward a couple of them here and I'll page
| | 08:22 | back a couple of them, and you notice
that it works, even for the first one.
| | 08:28 | And that's because we did this
replaceState as soon as we load it up.
| | 08:32 | We update the image, we set the title,
and we set the little app version there,
| | 08:37 | that's this string right here in our
little h1 tag. And you notice that that is
| | 08:42 | right here, appVersion. So that's it.
| | 08:46 | It's very, very simple.
| | 08:48 | The advantages of the HTML5
session history API are all present here.
| | 08:52 | Performance is maximized by keeping
network traffic to minimum, but each photo
| | 08:56 | has its own fully functional URL.
| | 09:00 | Click forward here to say the Mouse,
and I will just grab this URL and put it in
| | 09:05 | my Bookmark bar here.
| | 09:07 | And I can just bring up
Google.com, and when I click on Page:Mouse, there is it.
| | 09:14 | It's a completely functional bookmark,
and yet, as I press these buttons and as
| | 09:20 | I press the Back button up here, it's not
going out to the network and loading that up again.
| | 09:26 | So this is a common application for the
HTML5 session history API to use it for
| | 09:30 | a photo browser, and here we have it
fully implemented in less than 100 lines
| | 09:35 | of JavaScript.
| | Collapse this transcript |
|
|