This is a snapshot of an early working draft and has therefore been superseded by the HTML standard.

This document will not be further updated.

HTML 5

Call For Comments — 27 October 2007

4.7. Session history and navigation

4.7.1. The session history of browsing contexts

The sequence of Documents in a browsing context is its session history.

History objects provide a representation of the pages in the session history of browsing contexts. Each browsing context has a distinct session history.

Each Document object in a browsing context's session history is associated with a unique instance of the History object, although they all must model the same underlying session history.

The history attribute of the Window interface must return the object implementing the History interface for that Window object's active document.

History objects represent their browsing context's session history as a flat list of session history entries. Each session history entry consists of either a URI or a state object, or both, and may in addition have a title, a Document object, form data, a scroll position, and other information associated with it.

This does not imply that the user interface need be linear. See the notes below.

URIs without assaciated state objects are added to the session history as the user (or script) navigates from page to page.

A state object is an object representing a user interface state.

Pages can add state objects between their entry in the session history and the next ("forward") entry. These are then returned to the script when the user (or script) goes back in the history, thus enabling authors to use the "navigation" metaphor even in one-page applications.

At any point, one of the entries in the session history is the current entry. This is the entry representing the active document of the browsing context. The current entry is usually an entry for the location of the Document. However, it can also be one of the entries for state objects added to the history by that document.

Entries that consist of state objects share the same Document as the entry for the page that was active when they were added.

Contiguous entries that differ just by fragment identifier also share the same Document.

All entries that share the same Document (and that are therefore merely different states of one particular document) are contiguous by definition.

User agents may discard the DOMs of entries other than the current entry that are not referenced from any script, reloading the pages afresh when the user or script navigates back to such pages. This specification does not specify when user agents should discard pages' DOMs and when they should cache them. See the section on the load and unload events for more details.

Entries that have had their DOM discarded must, for the purposes of the algorithms given below, act as if they had not. When the user or script navigates back or forwards to a page which has no in-memory DOM objects, any other entries that shared the same Document object with it must share the new object as well.

When state object entries are added, a URI can be provided. This URI is used to replace the state object entry if the Document is evicted.

When a user agent discards the DOM from an entry in the session history, it must also discard all the entries that share that Document but do not have an associated URI (i.e. entries that only have a state object). Entries that shared that Document object but had a state object and have a different URI must then have their state objects removed. Removed entries are not recreated if the user or script navigates back to the page. If there are no state object entries for that Document object then no entries are removed.

4.7.2. The History interface

interface History {
  readonly attribute long length;
  void go(in long delta);
  void go();
  void back();
  void forward();
  void pushState(in DOMObject data, in DOMString title);
  void pushState(in DOMObject data, in DOMString title, in DOMString url);
  void clearState();
};

The length attribute of the History interface must return the number of entries in this session history.

The actual entries are not accessible from script.

The go(delta) method causes the UA to move the number of steps specified by delta in the session history.

If the index of the current entry plus delta is less than zero or greater than or equal to the number of items in the session history, then the user agent must do nothing.

If the delta is zero, then the user agent must act as if the location.reload() method was called instead.

Otherwise, the user agent must cause the current browsing context to traverse the history to the specified entry, as described below. The specified entry is the one whose index equals the index of the current entry plus delta.

When a user agent is required to traverse the history to a specified entry, the user agent must act as follows:

  1. If there is no longer a Document object for the entry in question, the user agent must navigate the browsing context to the location for that entry to preform an entry update of that entry, and abort these steps. The "navigate" algorithm reinvokes this "traverse" algorithm to complete the traversal, at which point there is a Document object and so this step gets skipped.
  2. If appropriate, update the current entry in the browsing context's Document object's History object to reflect any state that the user agent wishes to persist.

    For example, some user agents might want to persist the scroll position, or the values of form controls.

  3. If there are any entries with state objects between the current entry and the specified entry (not inclusive), then the user agent must iterate through every entry between the current entry and the specified entry, starting with the entry closest to the current entry, and ending with the one closest to the specified entry. For each entry, if the entry is a state object, the user agent must activate the state object.

  4. If the specified entry has a different Document object than the current entry then the user agent must run the following substeps:

    1. The user agent must move any properties that have been added to the browsing context's default view's Window object to the active document's Document's list of added properties.
    2. If the browsing context is a top-level browsing context (and not an auxiliary browsing context), and the origin of the Document of the specified entry is not the same as the origin of the Document of the current entry, then the following sub-sub-steps must be run:
      1. The current browsing context name must be stored with all the entries in the history that are associated with Document objects with the same origin as the active document and that are contiguous with the current entry.
      2. The browsing context's browsing context name must be unset.
    3. The user agent must make the specified entry's Document object the active document of the browsing context. (If it is a top-level browsing context, this might change which application cache it is associated with.)
    4. If the specified entry has a browsing context name stored with it, then the following sub-sub-steps must be run:
      1. The browsing context's browsing context name must be set to the name stored with the specified entry.
      2. Any browsing context name stored with the entries in the history that are associated with Document objects with the same origin as the new active document, and that are contiguous with the specified entry, must be cleared.
    5. The user agent must move any properties that have been added to the active document's Document's list of added properties to browsing context's default view's Window object.
  5. If the specified entry is a state object, the user agent must activate that state object.

  6. If the specified entry has a URI that differs from the current entry's only by its fragment identifier, and the two share the same Document object, then fire a simple event with the name hashchanged at the body element.

    I'm open to better event names and targets here.

  7. User agents may also update other aspects of the document view when the location changes in this way, for instance the scroll position, values of form fields, etc.

  8. The current entry is now the specified entry.

how does the changing of the global attributes affect .watch() when seen from other Windows?

When the user navigates through a browsing context, e.g. using a browser's back and forward buttons, the user agent must translate this action into the equivalent invocations of the history.go(delta) method on the various affected window objects.

Some of the other members of the History interface are defined in terms of the go() method, as follows:

Member Definition
go() Must do the same as go(0)
back() Must do the same as go(-1)
forward() Must do the same as go(1)

The pushState(data, title, url) method adds a state object to the history.

When this method is invoked, the user agent must first check the third argument. If a third argument is specified, then the user agent must verify that the third argument is a valid URI or IRI (as defined by RFC 3986 and 3987), and if so, that, after resolving it to an absolute URI, it is either identical to the document's URI, or that it differs from the document's URI only in the <query>, <abs_path>, and/or <fragment> parts, as applicable (the <query> and <abs_path> parts can only be the same if the document's URI uses a hierarchical <scheme>). If the verification fails (either because the argument is syntactically incorrect, or differs in a way not described as acceptable in the previous sentence) then the user agent must raise a security exception. [RFC3986] [RFC3987]

If the third argument passes its verification step, or if the third argument was omitted, then the user agent must remove from the session history any entries for that Document from the entry after the current entry up to the last entry in the session history that references the same Document object, if any. If the current entry is the last entry in the session history, or if there are no entries after the current entry that reference the same Document object, then no entries are removed.

Then, the user agent must add a state object entry to the session history, after the current entry, with the specified data as the state object, the given title as the title, and, if the third argument is present, the given url as the URI of the entry.

Finally, the user agent must update the current entry to be the this newly added entry.

The title is purely advisory. User agents might use the title in the user interface.

User agents may limit the number of state objects added to the session history per page. If a page hits the UA-defined limit, user agents must remove the entry immediately after the first entry for that Document object in the session history after having added the new entry. (Thus the state history acts as a FIFO buffer for eviction, but as a LIFO buffer for navigation.)

The clearState() method removes all the state objects for the Document object from the session history.

When this method is invoked, the user agent must remove from the session history all the entries from the first state object entry for that Document object up to the last entry that references that same Document object, if any.

Then, if the current entry was removed in the previous step, the current entry must be set to the last entry for that Document object in the session history.

4.7.3. Activating state objects

When a state object in the session history is activated (which happens in the cases described above), the user agent must fire a popstate event in no namespace on the the body element using the PopStateEvent interface, with the state object in the state attribute. This event bubbles but is not cancelable and has no default action.

interface PopStateEvent : Event {
  readonly attribute DOMObject state;
  void initPopStateEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMObject statetArg);
  void initPopStateEventNS(in DOMString namespaceURIArg, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMObject stateArg);
};

The initPopStateEvent() and initPopStateEventNS() methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]

The state attribute represents the context information for the event.

Should we coalesce these events if they occur while the page is away? (e.g. during traversal -- see above)

4.7.4. The Location interface

Each Document object in a browsing context's session history is associated with a unique instance of a Location object.

The location attribute of the HTMLDocument interface must return the Location object for that Document object.

The location attribute of the Window interface must return the Location object for that Window object's active document.

Location objects provide a representation of the URI of their document, and allow the current entry of the browsing context's session history to be changed, by adding or replacing entries in the history object.

interface Location {
  readonly attribute DOMString href;
  void assign(in DOMString url);
  void replace(in DOMString url);
  void reload();

  // URI decomposition attributes 
           attribute DOMString protocol;
           attribute DOMString host;
           attribute DOMString hostname;
           attribute DOMString port;
           attribute DOMString pathname;
           attribute DOMString search;
           attribute DOMString hash;
};

In the ECMAScript DOM binding, objects implementing this interface must stringify to the same value as the href attribute.

In the ECMAScript DOM binding, the location members of the HTMLDocument and Window interfaces behave as if they had a setter: user agents must treats attempts to set these location attribute as attempts at setting the href attribute of the relevant Location object instead.

The href attribute returns the address of the page represented by the associated Document object, as an absolute IRI reference.

On setting, the user agent must act as if the assign() method had been called with the new value as its argument.

When the assign(url) method is invoked, the UA must navigate the browsing context to the specified url.

When the replace(url) method is invoked, the UA must navigate to the specified url with replacement enabled.

Relative url arguments for assign() and replace() must be resolved relative to the base URI of the script that made the method call.

The Location interface also has the complement of URI decomposition attributes, protocol, host, port, hostname, pathname, search, and hash. These must follow the rules given for URI decomposition attributes, with the input being the address of the page represented by the associated Document object, as an absolute IRI reference (same as the href attribute), and the common setter action being the same as setting the href attribute to the new output value.

4.7.4.1. Security

User agents must raise a security exception whenever any of the members of a Location object are accessed by scripts whose origin is not the same as the Location object's associated Document's origin, with the following exceptions:

User agents must not allow scripts to override the href attribute's setter.

4.7.5. Implementation notes for session history

This section is non-normative.

The History interface is not meant to place restrictions on how implementations represent the session history to the user.

For example, session history could be implemented in a tree-like manner, with each page having multiple "forward" pages. This specification doesn't define how the linear list of pages in the history object are derived from the actual session history as seen from the user's perspective.

Similarly, a page containing two iframes has a history object distinct from the iframes' history objects, despite the fact that typical Web browsers present the user with just one "Back" button, with a session history that interleaves the navigation of the two inner frames and the outer page.

Security: It is suggested that to avoid letting a page "hijack" the history navigation facilities of a UA by abusing pushState(), the UA provide the user with a way to jump back to the previous page (rather than just going back to the previous state). For example, the back button could have a drop down showing just the pages in the session history, and not showing any of the states. Similarly, an aural browser could have two "back" commands, one that goes back to the previous state, and one that jumps straight back to the previous page.

In addition, a user agent could ignore calls to pushState() that are invoked on a timer, or from event handlers that do not represent a clear user action, or that are invoked in rapid succession.