OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview A collection of utility methods for UberPage and its contained | 6 * @fileoverview A collection of utility methods for UberPage and its contained |
7 * pages. | 7 * pages. |
8 */ | 8 */ |
9 | 9 |
10 cr.define('uber', function() { | 10 cr.define('uber', function() { |
11 | |
12 /** | 11 /** |
13 * Fixed position header elements on the page to be shifted by handleScroll. | 12 * Fixed position header elements on the page to be shifted by handleScroll. |
14 * @type {NodeList} | 13 * @type {NodeList} |
15 */ | 14 */ |
16 var headerElements; | 15 var headerElements; |
17 | 16 |
18 /** | 17 /** |
19 * This should be called by uber content pages when DOM content has loaded. | 18 * This should be called by uber content pages when DOM content has loaded. |
20 */ | 19 */ |
21 function onContentFrameLoaded() { | 20 function onContentFrameLoaded() { |
22 headerElements = document.getElementsByTagName('header'); | 21 headerElements = document.getElementsByTagName('header'); |
23 document.addEventListener('scroll', handleScroll); | 22 document.addEventListener('scroll', handleScroll); |
| 23 document.addEventListener('mousedown', handleMouseDownInFrame, true); |
24 | 24 |
25 invokeMethodOnParent('ready'); | 25 invokeMethodOnParent('ready'); |
26 | 26 |
27 // Prevent the navigation from being stuck in a disabled state when a | 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). | 28 // content page is reloaded while an overlay is visible (crbug.com/246939). |
29 invokeMethodOnParent('stopInterceptingEvents'); | 29 invokeMethodOnParent('stopInterceptingEvents'); |
30 | 30 |
31 // Trigger the scroll handler to tell the navigation if our page started | 31 // Trigger the scroll handler to tell the navigation if our page started |
32 // with some scroll (happens when you use tab restore). | 32 // with some scroll (happens when you use tab restore). |
33 handleScroll(); | 33 handleScroll(); |
34 | 34 |
35 window.addEventListener('message', handleWindowMessage); | 35 window.addEventListener('message', handleWindowMessage); |
36 } | 36 } |
37 | 37 |
38 /** | 38 /** |
39 * Handles scroll events on the document. This adjusts the position of all | 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. | 40 * headers and updates the parent frame when the page is scrolled. |
41 * @private | |
42 */ | 41 */ |
43 function handleScroll() { | 42 function handleScroll() { |
44 var scrollLeft = scrollLeftForDocument(document); | 43 var scrollLeft = scrollLeftForDocument(document); |
45 var offset = scrollLeft * -1; | 44 var offset = scrollLeft * -1; |
46 for (var i = 0; i < headerElements.length; i++) { | 45 for (var i = 0; i < headerElements.length; i++) { |
47 // As a workaround for http://crbug.com/231830, set the transform to | 46 // As a workaround for http://crbug.com/231830, set the transform to |
48 // 'none' rather than 0px. | 47 // 'none' rather than 0px. |
49 headerElements[i].style.webkitTransform = offset ? | 48 headerElements[i].style.webkitTransform = offset ? |
50 'translateX(' + offset + 'px)' : 'none'; | 49 'translateX(' + offset + 'px)' : 'none'; |
51 } | 50 } |
52 | 51 |
53 invokeMethodOnParent('adjustToScroll', scrollLeft); | 52 invokeMethodOnParent('adjustToScroll', scrollLeft); |
54 } | 53 } |
55 | 54 |
56 /** | 55 /** |
| 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. |
| 59 */ |
| 60 function handleMouseDownInFrame(e) { |
| 61 if (!e.isSynthetic && !document.hasFocus()) |
| 62 window.focus(); |
| 63 } |
| 64 |
| 65 /** |
57 * Handles 'message' events on window. | 66 * Handles 'message' events on window. |
58 * @param {Event} e The message event. | 67 * @param {Event} e The message event. |
59 */ | 68 */ |
60 function handleWindowMessage(e) { | 69 function handleWindowMessage(e) { |
61 e = /** @type {!MessageEvent.<!{method: string, params: *}>} */(e); | 70 e = /** @type {!MessageEvent.<!{method: string, params: *}>} */(e); |
62 if (e.data.method === 'frameSelected') { | 71 if (e.data.method === 'frameSelected') { |
63 handleFrameSelected(); | 72 handleFrameSelected(); |
64 } else if (e.data.method === 'mouseWheel') { | 73 } else if (e.data.method === 'mouseWheel') { |
65 handleMouseWheel( | 74 handleMouseWheel( |
66 /** @type {{deltaX: number, deltaY: number}} */(e.data.params)); | 75 /** @type {{deltaX: number, deltaY: number}} */(e.data.params)); |
67 } else if (e.data.method === 'mouseDown') { | 76 } else if (e.data.method === 'mouseDown') { |
68 handleMouseDown(); | 77 handleMouseDown(); |
69 } else if (e.data.method === 'popState') { | 78 } else if (e.data.method === 'popState') { |
70 handlePopState(e.data.params.state, e.data.params.path); | 79 handlePopState(e.data.params.state, e.data.params.path); |
71 } | 80 } |
72 } | 81 } |
73 | 82 |
74 /** | 83 /** |
75 * This is called when a user selects this frame via the navigation bar | 84 * This is called when a user selects this frame via the navigation bar |
76 * frame (and is triggered via postMessage() from the uber page). | 85 * frame (and is triggered via postMessage() from the uber page). |
77 * @private | |
78 */ | 86 */ |
79 function handleFrameSelected() { | 87 function handleFrameSelected() { |
80 setScrollTopForDocument(document, 0); | 88 setScrollTopForDocument(document, 0); |
81 } | 89 } |
82 | 90 |
83 /** | 91 /** |
84 * Called when a user mouse wheels (or trackpad scrolls) over the nav frame. | 92 * Called when a user mouse wheels (or trackpad scrolls) over the nav frame. |
85 * The wheel event is forwarded here and we scroll the body. | 93 * The wheel event is forwarded here and we scroll the body. |
86 * There's no way to figure out the actual scroll amount for a given delta. | 94 * There's no way to figure out the actual scroll amount for a given delta. |
87 * It differs for every platform and even initWebKitWheelEvent takes a | 95 * It differs for every platform and even initWebKitWheelEvent takes a |
88 * pixel amount instead of a wheel delta. So we just choose something | 96 * pixel amount instead of a wheel delta. So we just choose something |
89 * reasonable and hope no one notices the difference. | 97 * reasonable and hope no one notices the difference. |
90 * @param {{deltaX: number, deltaY: number}} params A structure that holds | 98 * @param {{deltaX: number, deltaY: number}} params A structure that holds |
91 * wheel deltas in X and Y. | 99 * wheel deltas in X and Y. |
92 */ | 100 */ |
93 function handleMouseWheel(params) { | 101 function handleMouseWheel(params) { |
94 window.scrollBy(-params.deltaX * 49 / 120, -params.deltaY * 49 / 120); | 102 window.scrollBy(-params.deltaX * 49 / 120, -params.deltaY * 49 / 120); |
95 } | 103 } |
96 | 104 |
97 /** | 105 /** |
98 * Fire a synthetic mousedown on the body to dismiss transient things like | 106 * Fire a synthetic mousedown on the body to dismiss transient things like |
99 * bubbles or menus that listen for mouse presses outside of their UI. We | 107 * bubbles or menus that listen for mouse presses outside of their UI. We |
100 * dispatch a fake mousedown rather than a 'mousepressedinnavframe' so that | 108 * dispatch a fake mousedown rather than a 'mousepressedinnavframe' so that |
101 * settings/history/extensions don't need to know about their embedder. | 109 * settings/history/extensions don't need to know about their embedder. |
102 */ | 110 */ |
103 function handleMouseDown() { | 111 function handleMouseDown() { |
104 document.body.dispatchEvent(new MouseEvent('mousedown')); | 112 var mouseEvent = new MouseEvent('mousedown'); |
| 113 mouseEvent.isSynthetic = true; |
| 114 document.dispatchEvent(mouseEvent); |
105 } | 115 } |
106 | 116 |
107 /** | 117 /** |
108 * Called when the parent window restores some state saved by uber.pushState | 118 * Called when the parent window restores some state saved by uber.pushState |
109 * or uber.replaceState. Simulates a popstate event. | 119 * or uber.replaceState. Simulates a popstate event. |
110 * @param {PopStateEvent} state A state object for replaceState and pushState. | 120 * @param {PopStateEvent} state A state object for replaceState and pushState. |
111 * @param {string} path The path the page navigated to. | 121 * @param {string} path The path the page navigated to. |
112 * @suppress {checkTypes} | 122 * @suppress {checkTypes} |
113 */ | 123 */ |
114 function handlePopState(state, path) { | 124 function handlePopState(state, path) { |
115 window.history.replaceState(state, '', path); | 125 window.history.replaceState(state, '', path); |
116 window.dispatchEvent(new PopStateEvent('popstate', {state: state})); | 126 window.dispatchEvent(new PopStateEvent('popstate', {state: state})); |
117 } | 127 } |
118 | 128 |
119 /** | 129 /** |
120 * @return {boolean} Whether this frame has a parent. | 130 * @return {boolean} Whether this frame has a parent. |
121 */ | 131 */ |
122 function hasParent() { | 132 function hasParent() { |
123 return window != window.parent; | 133 return window != window.parent; |
124 } | 134 } |
125 | 135 |
126 /** | 136 /** |
127 * Invokes a method on the parent window (UberPage). This is a convenience | 137 * Invokes a method on the parent window (UberPage). This is a convenience |
128 * method for API calls into the uber page. | 138 * method for API calls into the uber page. |
129 * @param {string} method The name of the method to invoke. | 139 * @param {string} method The name of the method to invoke. |
130 * @param {?=} opt_params Optional property bag of parameters to pass to the | 140 * @param {?=} opt_params Optional property bag of parameters to pass to the |
131 * invoked method. | 141 * invoked method. |
132 * @private | |
133 */ | 142 */ |
134 function invokeMethodOnParent(method, opt_params) { | 143 function invokeMethodOnParent(method, opt_params) { |
135 if (!hasParent()) | 144 if (!hasParent()) |
136 return; | 145 return; |
137 | 146 |
138 invokeMethodOnWindow(window.parent, method, opt_params, 'chrome://chrome'); | 147 invokeMethodOnWindow(window.parent, method, opt_params, 'chrome://chrome'); |
139 } | 148 } |
140 | 149 |
141 /** | 150 /** |
142 * Invokes a method on the target window. | 151 * Invokes a method on the target window. |
143 * @param {string} method The name of the method to invoke. | 152 * @param {string} method The name of the method to invoke. |
144 * @param {?=} opt_params Optional property bag of parameters to pass to the | 153 * @param {?=} opt_params Optional property bag of parameters to pass to the |
145 * invoked method. | 154 * invoked method. |
146 * @param {string=} opt_url The origin of the target window. | 155 * @param {string=} opt_url The origin of the target window. |
147 * @private | |
148 */ | 156 */ |
149 function invokeMethodOnWindow(targetWindow, method, opt_params, opt_url) { | 157 function invokeMethodOnWindow(targetWindow, method, opt_params, opt_url) { |
150 var data = {method: method, params: opt_params}; | 158 var data = {method: method, params: opt_params}; |
151 targetWindow.postMessage(data, opt_url ? opt_url : '*'); | 159 targetWindow.postMessage(data, opt_url ? opt_url : '*'); |
152 } | 160 } |
153 | 161 |
154 /** | 162 /** |
155 * Updates the page's history state. If the page is embedded in a child, | 163 * Updates the page's history state. If the page is embedded in a child, |
156 * forward the information to the parent for it to manage history for us. This | 164 * forward the information to the parent for it to manage history for us. This |
157 * is a replacement of history.replaceState and history.pushState. | 165 * is a replacement of history.replaceState and history.pushState. |
158 * @param {Object} state A state object for replaceState and pushState. | 166 * @param {Object} state A state object for replaceState and pushState. |
159 * @param {string} path The path the page navigated to. | 167 * @param {string} path The path the page navigated to. |
160 * @param {boolean} replace If true, navigate with replacement. | 168 * @param {boolean} replace If true, navigate with replacement. |
161 * @private | |
162 */ | 169 */ |
163 function updateHistory(state, path, replace) { | 170 function updateHistory(state, path, replace) { |
164 var historyFunction = replace ? | 171 var historyFunction = replace ? |
165 window.history.replaceState : | 172 window.history.replaceState : |
166 window.history.pushState; | 173 window.history.pushState; |
167 | 174 |
168 if (hasParent()) { | 175 if (hasParent()) { |
169 // If there's a parent, always replaceState. The parent will do the actual | 176 // If there's a parent, always replaceState. The parent will do the actual |
170 // pushState. | 177 // pushState. |
171 historyFunction = window.history.replaceState; | 178 historyFunction = window.history.replaceState; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 | 217 |
211 return { | 218 return { |
212 invokeMethodOnParent: invokeMethodOnParent, | 219 invokeMethodOnParent: invokeMethodOnParent, |
213 invokeMethodOnWindow: invokeMethodOnWindow, | 220 invokeMethodOnWindow: invokeMethodOnWindow, |
214 onContentFrameLoaded: onContentFrameLoaded, | 221 onContentFrameLoaded: onContentFrameLoaded, |
215 pushState: pushState, | 222 pushState: pushState, |
216 replaceState: replaceState, | 223 replaceState: replaceState, |
217 setTitle: setTitle, | 224 setTitle: setTitle, |
218 }; | 225 }; |
219 }); | 226 }); |
OLD | NEW |