/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html version: 3.3.0 build: 3167 */ YUI.add('history-html5', function(Y) { /** * Provides browser history management using the HTML5 history API. * * @module history * @submodule history-html5 * @since 3.2.0 */ /** *

* Provides browser history management using the HTML5 history API. *

* *

* When calling the add(), addValue(), * replace(), or replaceValue() methods on * HistoryHTML5, the following additional options are supported: *

* *
*
title (String)
*
* Title to use for the new history entry. Browsers will typically display * this title to the user in the detailed history window or in a dropdown * menu attached to the back/forward buttons. If not specified, the title * of the current document will be used. *
* *
url (String)
*
* URL to display to the user for the new history entry. This URL will be * visible in the browser's address bar and will be the bookmarked URL if * the user bookmarks the page. It may be a relative path ("foo/bar"), an * absolute path ("/foo/bar"), or a full URL ("http://example.com/foo/bar"). * If you specify a full URL, the origin must be the same as the * origin of the current page, or an error will occur. If no URL is * specified, the current URL will not be changed. *
*
* * @class HistoryHTML5 * @extends HistoryBase * @constructor * @param {Object} config (optional) Configuration object. The following * HistoryHTML5-specific properties are supported in addition to * those supported by HistoryBase: * *
*
enableSessionFallback (Boolean)
*
*

* Set this to true to store the most recent history state in * sessionStorage in order to seamlessly restore the previous state (if any) * when HistoryHTML5 is instantiated after a * window.onpopstate event has already fired. *

* *

* By default, this setting is false. *

*
*
*/ var HistoryBase = Y.HistoryBase, doc = Y.config.doc, win = Y.config.win, sessionStorage, useHistoryHTML5 = Y.config.useHistoryHTML5, JSON = Y.JSON || win.JSON, // prefer YUI JSON, but fall back to native ENABLE_FALLBACK = 'enableSessionFallback', SESSION_KEY = 'YUI_HistoryHTML5_state', SRC_POPSTATE = 'popstate', SRC_REPLACE = HistoryBase.SRC_REPLACE; function HistoryHTML5() { HistoryHTML5.superclass.constructor.apply(this, arguments); } Y.extend(HistoryHTML5, HistoryBase, { // -- Initialization ------------------------------------------------------- _init: function (config) { Y.on('popstate', this._onPopState, win, this); HistoryHTML5.superclass._init.apply(this, arguments); // If window.onload has already fired and the sessionStorage fallback is // enabled, try to restore the last state from sessionStorage. This // works around a shortcoming of the HTML5 history API: it's impossible // to get the current state if the popstate event fires before you've // subscribed to it. Since popstate fires immediately after onload, // the last state may be lost if you return to a page from another page. if (config && config[ENABLE_FALLBACK] && YUI.Env.windowLoaded) { // Gecko will throw an error if you attempt to reference // sessionStorage on a page served from a file:// URL, so we have to // be careful here. // // See http://yuilibrary.com/projects/yui3/ticket/2529165 try { sessionStorage = win.sessionStorage; } catch (ex) {} this._loadSessionState(); } }, // -- Protected Methods ---------------------------------------------------- /** * Returns a string unique to the current URL pathname that's suitable for * use as a session storage key. * * @method _getSessionKey * @return {String} * @protected */ _getSessionKey: function () { return SESSION_KEY + '_' + win.location.pathname; }, /** * Attempts to load a state entry stored in session storage. * * @method _loadSessionState * @protected */ _loadSessionState: function () { var lastState = JSON && sessionStorage && sessionStorage[this._getSessionKey()]; if (lastState) { try { this._resolveChanges(SRC_POPSTATE, JSON.parse(lastState) || null); } catch (ex) {} } }, /** * Stores the specified state entry in session storage if the * enableSessionFallback config property is true * and either Y.JSON or native JSON support is available and * session storage is supported. * * @method _storeSessionState * @param {mixed} state State to store. May be any type serializable to * JSON. * @protected */ _storeSessionState: function (state) { if (this._config[ENABLE_FALLBACK] && JSON && sessionStorage) { sessionStorage[this._getSessionKey()] = JSON.stringify(state || null); } }, /** * Overrides HistoryBase's _storeState() and pushes or replaces * a history entry using the HTML5 history API when necessary. * * @method _storeState * @param {String} src Source of the changes. * @param {Object} newState New state to store. * @param {Object} options Zero or more options. * @protected */ _storeState: function (src, newState, options) { if (src !== SRC_POPSTATE) { win.history[src === SRC_REPLACE ? 'replaceState' : 'pushState']( newState, options.title || doc.title || '', options.url || null ); } this._storeSessionState(newState); HistoryHTML5.superclass._storeState.apply(this, arguments); }, // -- Protected Event Handlers --------------------------------------------- /** * Handler for popstate events. * * @method _onPopState * @param {Event} e * @protected */ _onPopState: function (e) { var state = e._event.state; this._storeSessionState(state); this._resolveChanges(SRC_POPSTATE, state || null); } }, { // -- Public Static Properties --------------------------------------------- NAME: 'historyhtml5', /** * Constant used to identify state changes originating from * popstate events. * * @property SRC_POPSTATE * @type String * @static * @final */ SRC_POPSTATE: SRC_POPSTATE }); if (!Y.Node.DOM_EVENTS.popstate) { Y.Node.DOM_EVENTS.popstate = 1; } Y.HistoryHTML5 = HistoryHTML5; /** *

* If true, the Y.History alias will always point to * Y.HistoryHTML5 when the history-html5 module is loaded, even if * the current browser doesn't support HTML5 history. *

* *

* If false, the Y.History alias will always point to * Y.HistoryHash when the history-hash module is loaded, even if * the current browser supports HTML5 history. *

* *

* If neither true nor false, the * Y.History alias will point to the best available history adapter * that the browser supports. This is the default behavior. *

* * @property useHistoryHTML5 * @type boolean * @for config * @since 3.2.0 */ // HistoryHTML5 will always win over HistoryHash unless useHistoryHTML5 is false // or HTML5 history is not supported. if (useHistoryHTML5 === true || (useHistoryHTML5 !== false && HistoryBase.html5)) { Y.History = HistoryHTML5; } }, '3.3.0' ,{optional:['json'], requires:['event-base', 'history-base', 'node-base']});