summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources/uber/uber.js
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/resources/uber/uber.js')
-rw-r--r--chromium/chrome/browser/resources/uber/uber.js124
1 files changed, 98 insertions, 26 deletions
diff --git a/chromium/chrome/browser/resources/uber/uber.js b/chromium/chrome/browser/resources/uber/uber.js
index 44609c0d570..488310f8a30 100644
--- a/chromium/chrome/browser/resources/uber/uber.js
+++ b/chromium/chrome/browser/resources/uber/uber.js
@@ -21,6 +21,15 @@ cr.define('uber', function() {
var navFrame;
/**
+ * A queue of method invocations on one of the iframes; if the iframe has not
+ * loaded by the time there is a method to invoke, delay the invocation until
+ * it is ready.
+ * @type {Object}
+ * @private
+ */
+ var queuedInvokes = {};
+
+ /**
* Handles page initialization.
*/
function onLoad(e) {
@@ -92,8 +101,22 @@ cr.define('uber', function() {
* @param {Event} e The history event.
*/
function onPopHistoryState(e) {
- if (e.state && e.state.pageId)
- showPage(e.state.pageId, HISTORY_STATE_OPTION.NONE);
+ // Use the URL to determine which page to route to.
+ var params = resolvePageInfo();
+
+ // If the page isn't the current page, load it fresh. Even if the page is
+ // already loaded, it may have state not reflected in the URL, such as the
+ // history page's "Remove selected items" overlay. http://crbug.com/377386
+ if (getRequiredElement(params.id) !== getSelectedIframe())
+ showPage(params.id, HISTORY_STATE_OPTION.NONE, params.path);
+
+ // Either way, send the state down to it.
+ //
+ // Note: This assumes that the state and path parameters for every page
+ // under this origin are compatible. All of the downstream pages which
+ // navigate use pushState and replaceState.
+ invokeMethodOnPage(params.id, 'popState',
+ {state: e.state, path: '/' + params.path});
}
/**
@@ -126,24 +149,30 @@ cr.define('uber', function() {
* @param {Event} e The posted object.
*/
function handleWindowMessage(e) {
- if (e.data.method === 'beginInterceptingEvents')
+ if (e.data.method === 'beginInterceptingEvents') {
backgroundNavigation();
- else if (e.data.method === 'stopInterceptingEvents')
+ } else if (e.data.method === 'stopInterceptingEvents') {
foregroundNavigation();
- else if (e.data.method === 'setPath')
- setPath(e.origin, e.data.params.path);
- else if (e.data.method === 'setTitle')
+ } else if (e.data.method === 'ready') {
+ pageReady(e.origin);
+ } else if (e.data.method === 'updateHistory') {
+ updateHistory(e.origin, e.data.params.state, e.data.params.path,
+ e.data.params.replace);
+ } else if (e.data.method === 'setTitle') {
setTitle(e.origin, e.data.params.title);
- else if (e.data.method === 'showPage')
- showPage(e.data.params.pageId, HISTORY_STATE_OPTION.PUSH);
- else if (e.data.method === 'navigationControlsLoaded')
+ } else if (e.data.method === 'showPage') {
+ showPage(e.data.params.pageId,
+ HISTORY_STATE_OPTION.PUSH,
+ e.data.params.path);
+ } else if (e.data.method === 'navigationControlsLoaded') {
onNavigationControlsLoaded();
- else if (e.data.method === 'adjustToScroll')
+ } else if (e.data.method === 'adjustToScroll') {
adjustToScroll(e.data.params);
- else if (e.data.method === 'mouseWheel')
+ } else if (e.data.method === 'mouseWheel') {
forwardMouseWheel(e.data.params);
- else
+ } else {
console.error('Received unexpected message', e.data);
+ }
}
/**
@@ -192,10 +221,11 @@ cr.define('uber', function() {
/**
* Changes the path past the page title (i.e. chrome://chrome/settings/(.*)).
+ * @param {Object} state The page's state object for the navigation.
* @param {string} path The new /path/ to be set after the page name.
* @param {number} historyOption The type of history modification to make.
*/
- function changePathTo(path, historyOption) {
+ function changePathTo(state, path, historyOption) {
assert(!path || path.substr(-1) != '/', 'invalid path given');
var histFunc;
@@ -207,25 +237,31 @@ cr.define('uber', function() {
assert(histFunc, 'invalid historyOption given ' + historyOption);
var pageId = getSelectedIframe().id;
- var args = [{pageId: pageId}, '', '/' + pageId + '/' + (path || '')];
+ var args = [state, '', '/' + pageId + '/' + (path || '')];
histFunc.apply(window.history, args);
}
/**
- * Sets the "path" of the page (actually the path after the first '/' char).
- * @param {Object} origin The origin of the source iframe.
- * @param {string} title The new "path".
+ * Adds or replaces the current history entry based on a navigation from the
+ * source iframe.
+ * @param {string} origin The origin of the source iframe.
+ * @param {Object} state The source iframe's state object.
+ * @param {string} path The new "path" (e.g. "/createProfile").
+ * @param {boolean} replace Whether to replace the current history entry.
*/
- function setPath(origin, path) {
+ function updateHistory(origin, state, path, replace) {
assert(!path || path[0] != '/', 'invalid path sent from ' + origin);
+ var historyOption =
+ replace ? HISTORY_STATE_OPTION.REPLACE : HISTORY_STATE_OPTION.PUSH;
// Only update the currently displayed path if this is the visible frame.
- if (getIframeFromOrigin(origin).parentNode == getSelectedIframe())
- changePathTo(path, HISTORY_STATE_OPTION.REPLACE);
+ var container = getIframeFromOrigin(origin).parentNode;
+ if (container == getSelectedIframe())
+ changePathTo(state, path, historyOption);
}
/**
* Sets the title of the page.
- * @param {Object} origin The origin of the source iframe.
+ * @param {string} origin The origin of the source iframe.
* @param {string} title The title of the page.
*/
function setTitle(origin, title) {
@@ -241,21 +277,55 @@ cr.define('uber', function() {
}
/**
- * Selects a subpage. This is called from uber-frame.
- * @param {string} pageId Should matche an id of one of the iframe containers.
+ * Invokes a method on a subpage. If the subpage has not signaled readiness,
+ * queue the message for when it does.
+ * @param {string} pageId Should match an id of one of the iframe containers.
+ * @param {string} method The name of the method to invoke.
+ * @param {Object=} opt_params Optional property page of parameters to pass to
+ * the invoked method.
+ */
+ function invokeMethodOnPage(pageId, method, opt_params) {
+ var frame = $(pageId).querySelector('iframe');
+ if (!frame || !frame.dataset.ready) {
+ queuedInvokes[pageId] = (queuedInvokes[pageId] || []);
+ queuedInvokes[pageId].push([method, opt_params]);
+ } else {
+ uber.invokeMethodOnWindow(frame.contentWindow, method, opt_params);
+ }
+ }
+
+ /**
+ * Called in response to a page declaring readiness. Calls any deferred method
+ * invocations from invokeMethodOnPage.
+ * @param {string} origin The origin of the source iframe.
+ */
+ function pageReady(origin) {
+ var frame = getIframeFromOrigin(origin);
+ var container = frame.parentNode;
+ frame.dataset.ready = true;
+ var queue = queuedInvokes[container.id] || [];
+ queuedInvokes[container.id] = undefined;
+ for (var i = 0; i < queue.length; i++) {
+ uber.invokeMethodOnWindow(frame.contentWindow, queue[i][0], queue[i][1]);
+ }
+ }
+
+ /**
+ * Selects and navigates a subpage. This is called from uber-frame.
+ * @param {string} pageId Should match an id of one of the iframe containers.
* @param {integer} historyOption Indicates whether we should push or replace
* browser history.
* @param {string} path A sub-page path.
*/
function showPage(pageId, historyOption, path) {
var container = $(pageId);
- var lastSelected = document.querySelector('.iframe-container.selected');
// Lazy load of iframe contents.
var sourceUrl = container.dataset.url + (path || '');
var frame = container.querySelector('iframe');
if (!frame) {
frame = container.ownerDocument.createElement('iframe');
+ frame.name = pageId;
container.appendChild(frame);
frame.src = sourceUrl;
} else {
@@ -263,9 +333,11 @@ cr.define('uber', function() {
// content frame is as we don't have access to its contentWindow's
// location, so just replace every time until necessary to do otherwise.
frame.contentWindow.location.replace(sourceUrl);
+ frame.dataset.ready = false;
}
// If the last selected container is already showing, ignore the rest.
+ var lastSelected = document.querySelector('.iframe-container.selected');
if (lastSelected === container)
return;
@@ -295,7 +367,7 @@ cr.define('uber', function() {
uber.invokeMethodOnWindow(selectedFrame.contentWindow, 'frameSelected');
if (historyOption != HISTORY_STATE_OPTION.NONE)
- changePathTo(path, historyOption);
+ changePathTo({}, path, historyOption);
if (container.dataset.title)
document.title = container.dataset.title;