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 The menu that shows tabs from sessions on other devices. | 6 * @fileoverview The menu that shows tabs from sessions on other devices. |
7 */ | 7 */ |
8 | 8 |
9 cr.define('ntp', function() { | 9 cr.define('ntp', function() { |
10 'use strict'; | 10 'use strict'; |
11 | 11 |
12 var localStrings = new LocalStrings(); | 12 var localStrings = new LocalStrings(); |
13 var Menu = cr.ui.Menu; | 13 var Menu = cr.ui.Menu; |
14 var MenuItem = cr.ui.MenuItem; | 14 var MenuItem = cr.ui.MenuItem; |
15 var MenuButton = cr.ui.MenuButton; | 15 var MenuButton = cr.ui.MenuButton; |
16 var OtherSessionsMenuButton = cr.ui.define('button'); | 16 var OtherSessionsMenuButton = cr.ui.define('button'); |
17 | 17 |
18 // Histogram buckets for UMA tracking of menu usage. | 18 // Histogram buckets for UMA tracking of menu usage. |
19 var HISTOGRAM_EVENT = { | 19 var HISTOGRAM_EVENT = { |
20 INITIALIZED: 0, | 20 INITIALIZED: 0, |
21 SHOW_MENU: 1, | 21 SHOW_MENU: 1, |
22 LINK_CLICKED: 2, | 22 LINK_CLICKED: 2, |
23 LINK_RIGHT_CLICKED: 3 | 23 LINK_RIGHT_CLICKED: 3, |
24 SESSION_NAME_RIGHT_CLICKED: 4 | |
24 }; | 25 }; |
25 var HISTOGRAM_EVENT_LIMIT = HISTOGRAM_EVENT.LINK_RIGHT_CLICKED + 1; | 26 var HISTOGRAM_EVENT_LIMIT = HISTOGRAM_EVENT.SESSION_NAME_RIGHT_CLICKED + 1; |
26 | 27 |
27 OtherSessionsMenuButton.prototype = { | 28 OtherSessionsMenuButton.prototype = { |
28 __proto__: MenuButton.prototype, | 29 __proto__: MenuButton.prototype, |
29 | 30 |
30 decorate: function() { | 31 decorate: function() { |
31 MenuButton.prototype.decorate.call(this); | 32 MenuButton.prototype.decorate.call(this); |
32 this.menu = new Menu; | 33 this.menu = new Menu; |
33 cr.ui.decorate(this.menu, Menu); | 34 cr.ui.decorate(this.menu, Menu); |
34 this.menu.classList.add('footer-menu'); | 35 this.menu.classList.add('footer-menu'); |
35 this.menu.addEventListener('contextmenu', | 36 this.menu.addEventListener('contextmenu', |
36 this.onContextMenu_.bind(this), true); | 37 this.onContextMenu_.bind(this), true); |
37 document.body.appendChild(this.menu); | 38 document.body.appendChild(this.menu); |
38 | 39 |
40 // Create the context menu that appears when the user right clicks | |
41 // on a device name. | |
42 this.deviceContextMenu_ = DeviceContextMenu.getInstance().menu; | |
43 document.body.appendChild(this.deviceContextMenu_); | |
44 | |
39 this.promoMessage_ = $('other-sessions-promo-template').cloneNode(true); | 45 this.promoMessage_ = $('other-sessions-promo-template').cloneNode(true); |
40 this.promoMessage_.removeAttribute('id'); // Prevent a duplicate id. | 46 this.promoMessage_.removeAttribute('id'); // Prevent a duplicate id. |
41 | 47 |
42 this.sessions_ = []; | 48 this.sessions_ = []; |
43 this.anchorType = cr.ui.AnchorType.ABOVE; | 49 this.anchorType = cr.ui.AnchorType.ABOVE; |
44 this.invertLeftRight = true; | 50 this.invertLeftRight = true; |
45 | 51 |
46 this.recordUmaEvent_(HISTOGRAM_EVENT.INITIALIZED); | 52 this.recordUmaEvent_(HISTOGRAM_EVENT.INITIALIZED); |
47 }, | 53 }, |
48 | 54 |
(...skipping 11 matching lines...) Expand all Loading... | |
60 */ | 66 */ |
61 recordUmaEvent_: function(eventId) { | 67 recordUmaEvent_: function(eventId) { |
62 chrome.send('metricsHandler:recordInHistogram', | 68 chrome.send('metricsHandler:recordInHistogram', |
63 ['NewTabPage.OtherSessionsMenu', eventId, HISTOGRAM_EVENT_LIMIT]); | 69 ['NewTabPage.OtherSessionsMenu', eventId, HISTOGRAM_EVENT_LIMIT]); |
64 }, | 70 }, |
65 | 71 |
66 /** | 72 /** |
67 * Handle a context menu event for an object in the menu's DOM subtree. | 73 * Handle a context menu event for an object in the menu's DOM subtree. |
68 */ | 74 */ |
69 onContextMenu_: function(e) { | 75 onContextMenu_: function(e) { |
70 // Only record the action if it occurred in one of the menu items. | 76 // Only record the action if it occurred in one of the menu items or |
71 if (findAncestorByClass(e.target, 'footer-menu-item')) | 77 // on one of the session headings. |
78 if (findAncestorByClass(e.target, 'footer-menu-item')) { | |
72 this.recordUmaEvent_(HISTOGRAM_EVENT.LINK_RIGHT_CLICKED); | 79 this.recordUmaEvent_(HISTOGRAM_EVENT.LINK_RIGHT_CLICKED); |
80 } else if (findAncestorByClass(e.target, 'session-heading')) { | |
81 this.recordUmaEvent_( | |
82 HISTOGRAM_EVENT.SESSION_NAME_RIGHT_CLICKED); | |
83 | |
84 // Let the context menu know which session it was invoked on, | |
85 // since they all share the same instance of the menu. | |
86 DeviceContextMenu.getInstance().setSessionTag(e.target.sessionTag_); | |
87 } | |
73 }, | 88 }, |
74 | 89 |
75 /** | 90 /** |
91 * Hides the menu. | |
92 * @override | |
93 */ | |
94 hideMenu: function() { | |
95 // Don't hide if the device context menu is currently showing. | |
96 if (cr.ui.contextMenuHandler.menu != this.deviceContextMenu_) | |
97 MenuButton.prototype.hideMenu.call(this); | |
98 }, | |
99 | |
100 /** | |
76 * Shows the menu, first rebuilding it if necessary. | 101 * Shows the menu, first rebuilding it if necessary. |
77 * TODO(estade): the right of the menu should align with the right of the | 102 * TODO(estade): the right of the menu should align with the right of the |
78 * button. | 103 * button. |
79 * @override | 104 * @override |
80 */ | 105 */ |
81 showMenu: function() { | 106 showMenu: function() { |
82 if (this.sessions_.length == 0) | 107 if (this.sessions_.length == 0) |
83 chrome.send('getForeignSessions'); | 108 chrome.send('getForeignSessions'); |
84 this.recordUmaEvent_(HISTOGRAM_EVENT.SHOW_MENU); | 109 this.recordUmaEvent_(HISTOGRAM_EVENT.SHOW_MENU); |
85 MenuButton.prototype.showMenu.call(this); | 110 MenuButton.prototype.showMenu.call(this); |
(...skipping 27 matching lines...) Expand all Loading... | |
113 * Add the UI for a foreign session to the menu. | 138 * Add the UI for a foreign session to the menu. |
114 * @param {Object} session Object describing the foreign session. | 139 * @param {Object} session Object describing the foreign session. |
115 */ | 140 */ |
116 addSession_: function(session) { | 141 addSession_: function(session) { |
117 var doc = this.ownerDocument; | 142 var doc = this.ownerDocument; |
118 | 143 |
119 var section = doc.createElement('section'); | 144 var section = doc.createElement('section'); |
120 this.menu.appendChild(section); | 145 this.menu.appendChild(section); |
121 | 146 |
122 var heading = doc.createElement('h3'); | 147 var heading = doc.createElement('h3'); |
148 heading.classList.add('session-heading'); | |
Evan Stade
2012/03/30 21:00:30
className =
Patrick Dubroy
2012/03/30 21:21:20
Done.
| |
123 heading.textContent = session.name; | 149 heading.textContent = session.name; |
150 heading.sessionTag_ = session.tag; | |
124 section.appendChild(heading); | 151 section.appendChild(heading); |
125 | 152 |
153 var timeSpan = doc.createElement('span'); | |
154 timeSpan.classList.add('details'); | |
Evan Stade
2012/03/30 21:00:30
className =
Patrick Dubroy
2012/03/30 21:21:20
Done.
| |
155 timeSpan.textContent = session.modifiedTime; | |
156 heading.appendChild(timeSpan); | |
157 | |
158 cr.ui.contextMenuHandler.setContextMenu(heading, | |
159 this.deviceContextMenu_); | |
160 | |
126 for (var i = 0; i < session.windows.length; i++) { | 161 for (var i = 0; i < session.windows.length; i++) { |
127 var window = session.windows[i]; | 162 var window = session.windows[i]; |
163 | |
164 // Show a separator between multiple windows in the same session. | |
165 if (i > 0) | |
166 section.appendChild(doc.createElement('hr')); | |
167 | |
128 for (var j = 0; j < window.tabs.length; j++) { | 168 for (var j = 0; j < window.tabs.length; j++) { |
129 var tab = window.tabs[j]; | 169 var tab = window.tabs[j]; |
130 var a = doc.createElement('a'); | 170 var a = doc.createElement('a'); |
131 a.className = 'footer-menu-item'; | 171 a.className = 'footer-menu-item'; |
132 a.textContent = tab.title; | 172 a.textContent = tab.title; |
133 a.href = tab.url; | 173 a.href = tab.url; |
134 a.style.backgroundImage = 'url(chrome://favicon/' + tab.url + ')'; | 174 a.style.backgroundImage = 'url(chrome://favicon/' + tab.url + ')'; |
135 var clickHandler = this.makeClickHandler_( | 175 var clickHandler = this.makeClickHandler_( |
136 session.tag, String(window.sessionId), String(tab.sessionId)); | 176 session.tag, String(window.sessionId), String(tab.sessionId)); |
137 a.addEventListener('click', clickHandler); | 177 a.addEventListener('click', clickHandler); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
172 * @param {boolean} signedIn Is the user currently signed in? | 212 * @param {boolean} signedIn Is the user currently signed in? |
173 */ | 213 */ |
174 updateSignInState: function(signedIn) { | 214 updateSignInState: function(signedIn) { |
175 if (signedIn) | 215 if (signedIn) |
176 chrome.send('getForeignSessions'); | 216 chrome.send('getForeignSessions'); |
177 else | 217 else |
178 this.classList.add('invisible'); | 218 this.classList.add('invisible'); |
179 }, | 219 }, |
180 }; | 220 }; |
181 | 221 |
222 /** | |
223 * Context menu for device names in the list of sessions. | |
224 * This class is designed to be used as a singleton. | |
225 * | |
226 * @constructor | |
227 */ | |
228 function DeviceContextMenu() { | |
229 this.__proto__ = DeviceContextMenu.prototype; | |
230 this.initialize(); | |
231 } | |
232 cr.addSingletonGetter(DeviceContextMenu); | |
233 | |
234 DeviceContextMenu.prototype = { | |
235 | |
236 initialize: function() { | |
237 var menu = new cr.ui.Menu; | |
238 cr.ui.decorate(menu, cr.ui.Menu); | |
239 menu.classList.add('device-context-menu'); | |
240 menu.classList.add('footer-menu-context-menu'); | |
241 this.menu = menu; | |
242 this.hideItem_ = this.appendMenuItem_('hide'); | |
243 this.hideItem_.addEventListener('activate', this.onHide_.bind(this)); | |
244 }, | |
245 | |
246 /** | |
247 * Appends a menu item to |this.menu|. | |
248 * @param {String} textId The ID for the localized string that acts as | |
249 * the item's label. | |
250 */ | |
251 appendMenuItem_: function(textId) { | |
252 var button = cr.doc.createElement('button'); | |
253 this.menu.appendChild(button); | |
254 cr.ui.decorate(button, cr.ui.MenuItem); | |
255 button.textContent = localStrings.getString(textId); | |
256 return button; | |
257 }, | |
258 | |
259 /** | |
260 * Handler for the 'hide' menu item. | |
261 * @param {Event} e The activation event. | |
262 * @private | |
263 */ | |
264 onHide_: function(e) { | |
265 chrome.send('deleteForeignSession', [this.sessionTag_]); | |
266 chrome.send('getForeignSessions'); // Refresh the list. | |
267 }, | |
268 | |
269 /** | |
270 * Set the session tag which identifies the session that the context menu | |
271 * was invoked on. | |
272 * @param {String} tag The session tag. | |
273 */ | |
274 setSessionTag: function(tag) { | |
275 this.sessionTag_ = tag; | |
276 } | |
277 }; | |
278 | |
182 return { | 279 return { |
183 OtherSessionsMenuButton: OtherSessionsMenuButton, | 280 OtherSessionsMenuButton: OtherSessionsMenuButton, |
184 }; | 281 }; |
185 }); | 282 }); |
OLD | NEW |