Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3733)

Unified Diff: chrome/browser/resources/uber/uber.js

Issue 298553002: Options: maintain history entries on the parent frame. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More comments (try jobs on previous) Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/uber/uber.js
diff --git a/chrome/browser/resources/uber/uber.js b/chrome/browser/resources/uber/uber.js
index 5793ce3ca4bf0b77b50dcf3f913334b5951fa4e8..868758a83d82f15474e538499361a3f2b1a9560d 100644
--- a/chrome/browser/resources/uber/uber.js
+++ b/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 = {};
davidben 2014/05/19 22:38:33 This may not be strictly necessary? The only page
+
+ /**
* Handles page initialization.
*/
function onLoad(e) {
@@ -92,8 +101,26 @@ 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);
+ if (e.state && e.state.pageId) {
+ var params = resolvePageInfo();
+ assert(params.id === e.state.pageId);
+
+ // If the page doesn't exist, create it. Otherwise, swap it in.
+ var frame = $(params.id).querySelector('iframe');
+ if (!frame) {
+ showPage(params.id, HISTORY_STATE_OPTION.NONE, params.path);
+ } else {
+ selectPage(params.id);
+ }
Dan Beam 2014/05/19 23:06:49 nit: no curlies
davidben 2014/05/19 23:32:28 Done.
+
+ // 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(e.state.pageId, 'popState',
+ {state: e.state.pageState, path: params.path});
+ }
}
/**
@@ -130,8 +157,11 @@ cr.define('uber', function() {
backgroundNavigation();
} 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 === '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') {
@@ -195,10 +225,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;
@@ -210,25 +241,33 @@ cr.define('uber', function() {
assert(histFunc, 'invalid historyOption given ' + historyOption);
var pageId = getSelectedIframe().id;
- var args = [{pageId: pageId}, '', '/' + pageId + '/' + (path || '')];
+ var args = [{pageId: pageId, pageState: 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".
Dan Beam 2014/05/19 23:06:49 @param {string} path The new "path" (e.g. "/create
davidben 2014/05/19 23:32:28 Done.
+ * @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;
Dan Beam 2014/05/19 23:06:49 nit: 4 \s indent
davidben 2014/05/19 23:32:28 Done.
// Only update the currently displayed path if this is the visible frame.
- if (getIframeFromOrigin(origin).parentNode == getSelectedIframe())
- changePathTo(path, HISTORY_STATE_OPTION.REPLACE);
+ if (getIframeFromOrigin(origin).parentNode == getSelectedIframe()) {
+ changePathTo(state, path, historyOption);
+ }
Dan Beam 2014/05/19 23:06:49 nit: no curlies
davidben 2014/05/19 23:32:28 Done.
}
/**
* 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) {
@@ -244,7 +283,41 @@ cr.define('uber', function() {
}
/**
- * Selects a subpage. This is called from uber-frame.
+ * 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] || [];
+ delete queuedInvokes[container.id];
Dan Beam 2014/05/19 23:06:49 arguably this should be queuedInvokes[container
davidben 2014/05/19 23:32:28 Done.
+ 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.
@@ -252,7 +325,6 @@ cr.define('uber', function() {
*/
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 || '');
@@ -267,8 +339,23 @@ 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;
}
+ selectPage(pageId);
+
+ if (historyOption != HISTORY_STATE_OPTION.NONE)
+ changePathTo({}, path, historyOption);
+ }
+
+ /**
+ * Switches to a subpage. The subpage must already exist.
+ * @param {string} pageId Should match an id of one of the iframe containers.
+ */
+ function selectPage(pageId) {
+ var container = $(pageId);
Dan Beam 2014/05/19 23:06:49 nit: $ -> getRequiredElement
davidben 2014/05/19 23:32:28 Done.
Dan Beam 2014/05/19 23:49:10 I think you did this on L325 instead of L354
davidben 2014/05/20 00:12:55 Oops, so I did. Done.
+ var lastSelected = document.querySelector('.iframe-container.selected');
+
// If the last selected container is already showing, ignore the rest.
if (lastSelected === container)
return;
@@ -298,9 +385,6 @@ cr.define('uber', function() {
var selectedFrame = getSelectedIframe().querySelector('iframe');
uber.invokeMethodOnWindow(selectedFrame.contentWindow, 'frameSelected');
- if (historyOption != HISTORY_STATE_OPTION.NONE)
- changePathTo(path, historyOption);
-
if (container.dataset.title)
document.title = container.dataset.title;
$('favicon').href = 'chrome://theme/' + container.dataset.favicon;

Powered by Google App Engine
This is Rietveld 408576698