1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * @fileoverview A collection of utility methods for UberPage and its contained
10 cr
.define('uber', function() {
12 * Fixed position header elements on the page to be shifted by handleScroll.
18 * This should be called by uber content pages when DOM content has loaded.
20 function onContentFrameLoaded() {
21 headerElements
= document
.getElementsByTagName('header');
22 document
.addEventListener('scroll', handleScroll
);
23 document
.addEventListener('mousedown', handleMouseDownInFrame
, true);
25 invokeMethodOnParent('ready');
27 // Prevent the navigation from being stuck in a disabled state when a
28 // content page is reloaded while an overlay is visible (crbug.com/246939).
29 invokeMethodOnParent('stopInterceptingEvents');
31 // Trigger the scroll handler to tell the navigation if our page started
32 // with some scroll (happens when you use tab restore).
35 window
.addEventListener('message', handleWindowMessage
);
39 * Handles scroll events on the document. This adjusts the position of all
40 * headers and updates the parent frame when the page is scrolled.
42 function handleScroll() {
43 var scrollLeft
= scrollLeftForDocument(document
);
44 var offset
= scrollLeft
* -1;
45 for (var i
= 0; i
< headerElements
.length
; i
++) {
46 // As a workaround for http://crbug.com/231830, set the transform to
47 // 'none' rather than 0px.
48 headerElements
[i
].style
.webkitTransform
= offset
?
49 'translateX(' + offset
+ 'px)' : 'none';
52 invokeMethodOnParent('adjustToScroll', scrollLeft
);
56 * Tells the parent to focus the current frame if the mouse goes down in the
57 * current frame (and it doesn't already have focus).
58 * @param {Event} e A mousedown event.
60 function handleMouseDownInFrame(e
) {
61 if (!e
.isSynthetic
&& !document
.hasFocus())
66 * Handles 'message' events on window.
67 * @param {Event} e The message event.
69 function handleWindowMessage(e
) {
70 e
= /** @type {!MessageEvent<!{method: string, params: *}>} */(e
);
71 if (e
.data
.method
=== 'frameSelected') {
72 handleFrameSelected();
73 } else if (e
.data
.method
=== 'mouseWheel') {
75 /** @type {{deltaX: number, deltaY: number}} */(e
.data
.params
));
76 } else if (e
.data
.method
=== 'mouseDown') {
78 } else if (e
.data
.method
=== 'popState') {
79 handlePopState(e
.data
.params
.state
, e
.data
.params
.path
);
84 * This is called when a user selects this frame via the navigation bar
85 * frame (and is triggered via postMessage() from the uber page).
87 function handleFrameSelected() {
88 setScrollTopForDocument(document
, 0);
92 * Called when a user mouse wheels (or trackpad scrolls) over the nav frame.
93 * The wheel event is forwarded here and we scroll the body.
94 * There's no way to figure out the actual scroll amount for a given delta.
95 * It differs for every platform and even initWebKitWheelEvent takes a
96 * pixel amount instead of a wheel delta. So we just choose something
97 * reasonable and hope no one notices the difference.
98 * @param {{deltaX: number, deltaY: number}} params A structure that holds
99 * wheel deltas in X and Y.
101 function handleMouseWheel(params
) {
102 window
.scrollBy(-params
.deltaX
* 49 / 120, -params
.deltaY
* 49 / 120);
106 * Fire a synthetic mousedown on the body to dismiss transient things like
107 * bubbles or menus that listen for mouse presses outside of their UI. We
108 * dispatch a fake mousedown rather than a 'mousepressedinnavframe' so that
109 * settings/history/extensions don't need to know about their embedder.
111 function handleMouseDown() {
112 var mouseEvent
= new MouseEvent('mousedown');
113 mouseEvent
.isSynthetic
= true;
114 document
.dispatchEvent(mouseEvent
);
118 * Called when the parent window restores some state saved by uber.pushState
119 * or uber.replaceState. Simulates a popstate event.
120 * @param {PopStateEvent} state A state object for replaceState and pushState.
121 * @param {string} path The path the page navigated to.
122 * @suppress {checkTypes}
124 function handlePopState(state
, path
) {
125 window
.history
.replaceState(state
, '', path
);
126 window
.dispatchEvent(new PopStateEvent('popstate', {state
: state
}));
130 * @return {boolean} Whether this frame has a parent.
132 function hasParent() {
133 return window
!= window
.parent
;
137 * Invokes a method on the parent window (UberPage). This is a convenience
138 * method for API calls into the uber page.
139 * @param {string} method The name of the method to invoke.
140 * @param {?=} opt_params Optional property bag of parameters to pass to the
143 function invokeMethodOnParent(method
, opt_params
) {
147 invokeMethodOnWindow(window
.parent
, method
, opt_params
, 'chrome://chrome');
151 * Invokes a method on the target window.
152 * @param {string} method The name of the method to invoke.
153 * @param {?=} opt_params Optional property bag of parameters to pass to the
155 * @param {string=} opt_url The origin of the target window.
157 function invokeMethodOnWindow(targetWindow
, method
, opt_params
, opt_url
) {
158 var data
= {method
: method
, params
: opt_params
};
159 targetWindow
.postMessage(data
, opt_url
? opt_url
: '*');
163 * Updates the page's history state. If the page is embedded in a child,
164 * forward the information to the parent for it to manage history for us. This
165 * is a replacement of history.replaceState and history.pushState.
166 * @param {Object} state A state object for replaceState and pushState.
167 * @param {string} path The path the page navigated to.
168 * @param {boolean} replace If true, navigate with replacement.
170 function updateHistory(state
, path
, replace
) {
171 var historyFunction
= replace
?
172 window
.history
.replaceState
:
173 window
.history
.pushState
;
176 // If there's a parent, always replaceState. The parent will do the actual
178 historyFunction
= window
.history
.replaceState
;
179 invokeMethodOnParent('updateHistory', {
180 state
: state
, path
: path
, replace
: replace
});
182 historyFunction
.call(window
.history
, state
, '', '/' + path
);
186 * Sets the current title for the page. If the page is embedded in a child,
187 * forward the information to the parent. This is a replacement for setting
189 * @param {string} title The new title for the page.
191 function setTitle(title
) {
192 document
.title
= title
;
193 invokeMethodOnParent('setTitle', {title
: title
});
197 * Pushes new history state for the page. If the page is embedded in a child,
198 * forward the information to the parent; when embedded, all history entries
199 * are attached to the parent. This is a replacement of history.pushState.
200 * @param {Object} state A state object for replaceState and pushState.
201 * @param {string} path The path the page navigated to.
203 function pushState(state
, path
) {
204 updateHistory(state
, path
, false);
208 * Replaces the page's history state. If the page is embedded in a child,
209 * forward the information to the parent; when embedded, all history entries
210 * are attached to the parent. This is a replacement of history.replaceState.
211 * @param {Object} state A state object for replaceState and pushState.
212 * @param {string} path The path the page navigated to.
214 function replaceState(state
, path
) {
215 updateHistory(state
, path
, true);
219 invokeMethodOnParent
: invokeMethodOnParent
,
220 invokeMethodOnWindow
: invokeMethodOnWindow
,
221 onContentFrameLoaded
: onContentFrameLoaded
,
222 pushState
: pushState
,
223 replaceState
: replaceState
,