blob: 9e823f0326775776197a92bf87de9ccae41a8ada [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview Navigation related APIs.
*/
goog.provide('__crWeb.navigation');
/** Beginning of anonymouse object */
(function() {
/**
* A popstate event needs to be fired anytime the active history entry
* changes without an associated document change. Either via back, forward, go
* navigation or by loading the URL, clicking on a link, etc.
*/
__gCrWeb['dispatchPopstateEvent'] = function(stateObject) {
var popstateEvent = window.document.createEvent('HTMLEvents');
popstateEvent.initEvent('popstate', true, false);
if (stateObject)
popstateEvent.state = JSON.parse(stateObject);
// setTimeout() is used in order to return immediately. Otherwise the
// dispatchEvent call waits for all event handlers to return, which could
// cause a ReentryGuard failure.
window.setTimeout(function() {
window.dispatchEvent(popstateEvent);
}, 0);
};
/**
* A hashchange event needs to be fired after a same-document history
* navigation between two URLs that are equivalent except for their fragments.
*/
__gCrWeb['dispatchHashchangeEvent'] = function(oldURL, newURL) {
var hashchangeEvent = window.document.createEvent('HTMLEvents');
hashchangeEvent.initEvent('hashchange', true, false);
if (oldURL)
hashchangeEvent.oldURL = oldURL;
if (newURL)
hashchangeEvent.newURL = newURL
// setTimeout() is used in order to return immediately. Otherwise the
// dispatchEvent call waits for all event handlers to return, which could
// cause a ReentryGuard failure.
window.setTimeout(function() {
window.dispatchEvent(hashchangeEvent);
}, 0);
};
/**
* Keep the original pushState() and replaceState() methods. It's needed to
* update the web view's URL and window.history.state property during history
* navigations that don't cause a page load.
* @private
*/
var originalWindowHistoryPushState = window.history.pushState;
var originalWindowHistoryReplaceState = window.history.replaceState;
__gCrWeb['replaceWebViewURL'] = function(url, stateObject) {
originalWindowHistoryReplaceState.call(history, stateObject, '', url);
};
/**
* Intercept window.history methods to call back/forward natively.
*/
window.history.back = function() {
__gCrWeb.message.invokeOnHost({'command': 'window.history.back'});
};
window.history.forward = function() {
__gCrWeb.message.invokeOnHost({'command': 'window.history.forward'});
};
window.history.go = function(delta) {
__gCrWeb.message.invokeOnHost(
{'command': 'window.history.go', 'value': delta | 0});
};
window.history.pushState = function(stateObject, pageTitle, pageUrl) {
__gCrWeb.message.invokeOnHost(
{'command': 'window.history.willChangeState'});
// Calling stringify() on undefined causes a JSON parse error.
var serializedState =
typeof(stateObject) == 'undefined' ? '' :
__gCrWeb.common.JSONStringify(stateObject);
pageUrl = pageUrl || window.location.href;
originalWindowHistoryPushState.call(history, stateObject,
pageTitle, pageUrl);
__gCrWeb.message.invokeOnHost(
{'command': 'window.history.didPushState',
'stateObject': serializedState,
'baseUrl': document.baseURI,
'pageUrl': pageUrl.toString()});
};
window.history.replaceState = function(stateObject, pageTitle, pageUrl) {
__gCrWeb.message.invokeOnHost(
{'command': 'window.history.willChangeState'});
// Calling stringify() on undefined causes a JSON parse error.
var serializedState =
typeof(stateObject) == 'undefined' ? '' :
__gCrWeb.common.JSONStringify(stateObject);
pageUrl = pageUrl || window.location.href;
originalWindowHistoryReplaceState.call(history, stateObject,
pageTitle, pageUrl);
__gCrWeb.message.invokeOnHost(
{'command': 'window.history.didReplaceState',
'stateObject': serializedState,
'baseUrl': document.baseURI,
'pageUrl': pageUrl.toString()});
};
window.addEventListener('hashchange', function(evt) {
// Because hash changes don't trigger __gCrWeb.didFinishNavigation, so fetch
// favicons for the new page manually.
__gCrWeb.message.invokeOnHost({'command': 'document.favicons',
'favicons': __gCrWeb.common.getFavicons()});
__gCrWeb.message.invokeOnHost({'command': 'window.hashchange'});
});
/** Flush the message queue. */
if (__gCrWeb.message) {
__gCrWeb.message.invokeQueues();
}
}()); // End of anonymouse object