blob: 2a712b60c295ee8def5966291d6773afc5f184ea [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() {
/**
* 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;
function DataCloneError() {
// The name and code for this error are defined by the WebIDL spec. See
// https://heycam.github.io/webidl/#datacloneerror
this.name = 'DataCloneError';
this.code = 25;
this.message = "Cyclic structures are not supported.";
}
/**
* Intercepts window.history methods so native code can differentiate between
* same-document navigation that are state navigations vs. hash navigations.
* This is needed for backward compatibility of DidStartLoading, which is
* triggered for fragment navigation but not state navigation.
* TODO(crbug.com/783382): Remove this once DidStartLoading is no longer
* called for same-document navigation.
*/
window.history.pushState = function(stateObject, pageTitle, pageUrl) {
__gCrWeb.message.invokeOnHost({'command': 'navigation.willChangeState'});
// JSONStringify throws an exception when given a cyclical object. This
// internal implementation detail should not be exposed to callers of
// pushState. Instead, throw a standard exception when stringification fails.
try {
// Calling stringify() on undefined causes a JSON parse error.
var serializedState = typeof (stateObject) == 'undefined' ?
'' :
__gCrWeb.common.JSONStringify(stateObject);
} catch (e) {
throw new DataCloneError();
}
pageUrl = pageUrl || window.location.href;
originalWindowHistoryPushState.call(history, stateObject, pageTitle, pageUrl);
__gCrWeb.message.invokeOnHost({
'command': 'navigation.didPushState',
'stateObject': serializedState,
'baseUrl': document.baseURI,
'pageUrl': pageUrl.toString()
});
};
window.history.replaceState = function(stateObject, pageTitle, pageUrl) {
__gCrWeb.message.invokeOnHost({'command': 'navigation.willChangeState'});
// JSONStringify throws an exception when given a cyclical object. This
// internal implementation detail should not be exposed to callers of
// replaceState. Instead, throw a standard exception when stringification
// fails.
try {
// Calling stringify() on undefined causes a JSON parse error.
var serializedState = typeof (stateObject) == 'undefined' ?
'' :
__gCrWeb.common.JSONStringify(stateObject);
} catch (e) {
throw new DataCloneError();
}
pageUrl = pageUrl || window.location.href;
originalWindowHistoryReplaceState.call(
history, stateObject, pageTitle, pageUrl);
__gCrWeb.message.invokeOnHost({
'command': 'navigation.didReplaceState',
'stateObject': serializedState,
'baseUrl': document.baseURI,
'pageUrl': pageUrl.toString()
});
};
window.addEventListener('hashchange', function(evt) {
__gCrWeb.message.invokeOnHost({'command': 'navigation.hashchange'});
});
/** Flush the message queue. */
if (__gCrWeb.message) {
__gCrWeb.message.invokeQueues();
}
}()); // End of anonymouse object