123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- // Copyright 2010 The Closure Library Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS-IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- /**
- * @fileoverview HTML5 based history implementation, compatible with
- * goog.History.
- *
- * TODO(user): There should really be a history interface and multiple
- * implementations.
- *
- */
- goog.provide('goog.history.Html5History');
- goog.provide('goog.history.Html5History.TokenTransformer');
- goog.require('goog.asserts');
- goog.require('goog.events');
- goog.require('goog.events.EventTarget');
- goog.require('goog.events.EventType');
- goog.require('goog.history.Event');
- /**
- * An implementation compatible with goog.History that uses the HTML5
- * history APIs.
- *
- * @param {Window=} opt_win The window to listen/dispatch history events on.
- * @param {goog.history.Html5History.TokenTransformer=} opt_transformer
- * The token transformer that is used to create URL from the token
- * when storing token without using hash fragment.
- * @constructor
- * @extends {goog.events.EventTarget}
- * @final
- */
- goog.history.Html5History = function(opt_win, opt_transformer) {
- goog.events.EventTarget.call(this);
- goog.asserts.assert(
- goog.history.Html5History.isSupported(opt_win),
- 'HTML5 history is not supported.');
- /**
- * The window object to use for history tokens. Typically the top window.
- * @type {Window}
- * @private
- */
- this.window_ = opt_win || window;
- /**
- * The token transformer that is used to create URL from the token
- * when storing token without using hash fragment.
- * @type {goog.history.Html5History.TokenTransformer}
- * @private
- */
- this.transformer_ = opt_transformer || null;
- /**
- * The fragment of the last navigation. Used to eliminate duplicate/redundant
- * NAVIGATE events when a POPSTATE and HASHCHANGE event are triggered for the
- * same navigation (e.g., back button click).
- * @private {?string}
- */
- this.lastFragment_ = null;
- goog.events.listen(
- this.window_, goog.events.EventType.POPSTATE, this.onHistoryEvent_, false,
- this);
- goog.events.listen(
- this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
- false, this);
- };
- goog.inherits(goog.history.Html5History, goog.events.EventTarget);
- /**
- * Returns whether Html5History is supported.
- * @param {Window=} opt_win Optional window to check.
- * @return {boolean} Whether html5 history is supported.
- */
- goog.history.Html5History.isSupported = function(opt_win) {
- var win = opt_win || window;
- return !!(win.history && win.history.pushState);
- };
- /**
- * Status of when the object is active and dispatching events.
- * @type {boolean}
- * @private
- */
- goog.history.Html5History.prototype.enabled_ = false;
- /**
- * Whether to use the fragment to store the token, defaults to true.
- * @type {boolean}
- * @private
- */
- goog.history.Html5History.prototype.useFragment_ = true;
- /**
- * If useFragment is false the path will be used, the path prefix will be
- * prepended to all tokens. Defaults to '/'.
- * @type {string}
- * @private
- */
- goog.history.Html5History.prototype.pathPrefix_ = '/';
- /**
- * Starts or stops the History. When enabled, the History object
- * will immediately fire an event for the current location. The caller can set
- * up event listeners between the call to the constructor and the call to
- * setEnabled.
- *
- * @param {boolean} enable Whether to enable history.
- */
- goog.history.Html5History.prototype.setEnabled = function(enable) {
- if (enable == this.enabled_) {
- return;
- }
- this.enabled_ = enable;
- if (enable) {
- this.dispatchEvent(new goog.history.Event(this.getToken(), false));
- }
- };
- /**
- * Returns the current token.
- * @return {string} The current token.
- */
- goog.history.Html5History.prototype.getToken = function() {
- if (this.useFragment_) {
- return goog.asserts.assertString(this.getFragment_());
- } else {
- return this.transformer_ ?
- this.transformer_.retrieveToken(
- this.pathPrefix_, this.window_.location) :
- this.window_.location.pathname.substr(this.pathPrefix_.length);
- }
- };
- /**
- * Sets the history state.
- * @param {string} token The history state identifier.
- * @param {string=} opt_title Optional title to associate with history entry.
- */
- goog.history.Html5History.prototype.setToken = function(token, opt_title) {
- if (token == this.getToken()) {
- return;
- }
- // Per externs/gecko_dom.js document.title can be null.
- this.window_.history.pushState(
- null, opt_title || this.window_.document.title || '',
- this.getUrl_(token));
- this.dispatchEvent(new goog.history.Event(token, false));
- };
- /**
- * Replaces the current history state without affecting the rest of the history
- * stack.
- * @param {string} token The history state identifier.
- * @param {string=} opt_title Optional title to associate with history entry.
- */
- goog.history.Html5History.prototype.replaceToken = function(token, opt_title) {
- // Per externs/gecko_dom.js document.title can be null.
- this.window_.history.replaceState(
- null, opt_title || this.window_.document.title || '',
- this.getUrl_(token));
- this.dispatchEvent(new goog.history.Event(token, false));
- };
- /** @override */
- goog.history.Html5History.prototype.disposeInternal = function() {
- goog.events.unlisten(
- this.window_, goog.events.EventType.POPSTATE, this.onHistoryEvent_, false,
- this);
- if (this.useFragment_) {
- goog.events.unlisten(
- this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
- false, this);
- }
- };
- /**
- * Sets whether to use the fragment to store tokens.
- * @param {boolean} useFragment Whether to use the fragment.
- */
- goog.history.Html5History.prototype.setUseFragment = function(useFragment) {
- if (this.useFragment_ != useFragment) {
- if (useFragment) {
- goog.events.listen(
- this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
- false, this);
- } else {
- goog.events.unlisten(
- this.window_, goog.events.EventType.HASHCHANGE, this.onHistoryEvent_,
- false, this);
- }
- this.useFragment_ = useFragment;
- }
- };
- /**
- * Sets the path prefix to use if storing tokens in the path. The path
- * prefix should start and end with slash.
- * @param {string} pathPrefix Sets the path prefix.
- */
- goog.history.Html5History.prototype.setPathPrefix = function(pathPrefix) {
- this.pathPrefix_ = pathPrefix;
- };
- /**
- * Gets the path prefix.
- * @return {string} The path prefix.
- */
- goog.history.Html5History.prototype.getPathPrefix = function() {
- return this.pathPrefix_;
- };
- /**
- * Gets the current hash fragment, if useFragment_ is enabled.
- * @return {?string} The hash fragment.
- * @private
- */
- goog.history.Html5History.prototype.getFragment_ = function() {
- if (this.useFragment_) {
- var loc = this.window_.location.href;
- var index = loc.indexOf('#');
- return index < 0 ? '' : loc.substring(index + 1);
- } else {
- return null;
- }
- };
- /**
- * Gets the URL to set when calling history.pushState
- * @param {string} token The history token.
- * @return {string} The URL.
- * @private
- */
- goog.history.Html5History.prototype.getUrl_ = function(token) {
- if (this.useFragment_) {
- return '#' + token;
- } else {
- return this.transformer_ ?
- this.transformer_.createUrl(
- token, this.pathPrefix_, this.window_.location) :
- this.pathPrefix_ + token + this.window_.location.search;
- }
- };
- /**
- * Handles history events dispatched by the browser.
- * @param {goog.events.BrowserEvent} e The browser event object.
- * @private
- */
- goog.history.Html5History.prototype.onHistoryEvent_ = function(e) {
- if (this.enabled_) {
- var fragment = this.getFragment_();
- // Only fire NAVIGATE event if it's POPSTATE or if the fragment has changed
- // without a POPSTATE event. The latter is an indication the browser doesn't
- // support POPSTATE, and the event is a HASHCHANGE instead.
- if (e.type == goog.events.EventType.POPSTATE ||
- fragment != this.lastFragment_) {
- this.lastFragment_ = fragment;
- this.dispatchEvent(new goog.history.Event(this.getToken(), true));
- }
- }
- };
- /**
- * A token transformer that can create a URL from a history
- * token. This is used by {@code goog.history.Html5History} to create
- * URL when storing token without the hash fragment.
- *
- * Given a {@code window.location} object containing the location
- * created by {@code createUrl}, the token transformer allows
- * retrieval of the token back via {@code retrieveToken}.
- *
- * @interface
- */
- goog.history.Html5History.TokenTransformer = function() {};
- /**
- * Retrieves a history token given the path prefix and
- * {@code window.location} object.
- *
- * @param {string} pathPrefix The path prefix to use when storing token
- * in a path; always begin with a slash.
- * @param {Location} location The {@code window.location} object.
- * Treat this object as read-only.
- * @return {string} token The history token.
- */
- goog.history.Html5History.TokenTransformer.prototype.retrieveToken = function(
- pathPrefix, location) {};
- /**
- * Creates a URL to be pushed into HTML5 history stack when storing
- * token without using hash fragment.
- *
- * @param {string} token The history token.
- * @param {string} pathPrefix The path prefix to use when storing token
- * in a path; always begin with a slash.
- * @param {Location} location The {@code window.location} object.
- * Treat this object as read-only.
- * @return {string} url The complete URL string from path onwards
- * (without {@code protocol://host:port} part); must begin with a
- * slash.
- */
- goog.history.Html5History.TokenTransformer.prototype.createUrl = function(
- token, pathPrefix, location) {};
|