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 { | |
81 var heading = findAncestorByClass(e.target, 'session-heading'); | |
82 if (heading) { | |
83 this.recordUmaEvent_(HISTOGRAM_EVENT.SESSION_NAME_RIGHT_CLICKED); | |
84 | |
85 // Let the context menu know which session it was invoked on, | |
86 // since they all share the same instance of the menu. | |
87 DeviceContextMenu.getInstance().setSessionTag(heading.sessionTag_); | |
88 } | |
89 } | |
73 }, | 90 }, |
74 | 91 |
75 /** | 92 /** |
93 * Hides the menu. | |
94 * @override | |
95 */ | |
96 hideMenu: function() { | |
97 // Don't hide if the device context menu is currently showing. | |
98 if (cr.ui.contextMenuHandler.menu != this.deviceContextMenu_) | |
99 MenuButton.prototype.hideMenu.call(this); | |
100 }, | |
101 | |
102 /** | |
76 * Shows the menu, first rebuilding it if necessary. | 103 * Shows the menu, first rebuilding it if necessary. |
77 * TODO(estade): the right of the menu should align with the right of the | 104 * TODO(estade): the right of the menu should align with the right of the |
78 * button. | 105 * button. |
79 * @override | 106 * @override |
80 */ | 107 */ |
81 showMenu: function() { | 108 showMenu: function() { |
82 if (this.sessions_.length == 0) | 109 if (this.sessions_.length == 0) |
83 chrome.send('getForeignSessions'); | 110 chrome.send('getForeignSessions'); |
84 this.recordUmaEvent_(HISTOGRAM_EVENT.SHOW_MENU); | 111 this.recordUmaEvent_(HISTOGRAM_EVENT.SHOW_MENU); |
85 MenuButton.prototype.showMenu.call(this); | 112 MenuButton.prototype.showMenu.call(this); |
(...skipping 27 matching lines...) Expand all Loading... | |
113 * Add the UI for a foreign session to the menu. | 140 * Add the UI for a foreign session to the menu. |
114 * @param {Object} session Object describing the foreign session. | 141 * @param {Object} session Object describing the foreign session. |
115 */ | 142 */ |
116 addSession_: function(session) { | 143 addSession_: function(session) { |
117 var doc = this.ownerDocument; | 144 var doc = this.ownerDocument; |
118 | 145 |
119 var section = doc.createElement('section'); | 146 var section = doc.createElement('section'); |
120 this.menu.appendChild(section); | 147 this.menu.appendChild(section); |
121 | 148 |
122 var heading = doc.createElement('h3'); | 149 var heading = doc.createElement('h3'); |
150 heading.className = 'session-heading'; | |
123 heading.textContent = session.name; | 151 heading.textContent = session.name; |
152 heading.sessionTag_ = session.tag; | |
124 section.appendChild(heading); | 153 section.appendChild(heading); |
125 | 154 |
155 var timeSpan = doc.createElement('span'); | |
156 timeSpan.className = 'details'; | |
157 timeSpan.textContent = session.modifiedTime; | |
158 heading.appendChild(timeSpan); | |
159 | |
160 cr.ui.contextMenuHandler.setContextMenu(heading, | |
161 this.deviceContextMenu_); | |
162 | |
126 for (var i = 0; i < session.windows.length; i++) { | 163 for (var i = 0; i < session.windows.length; i++) { |
127 var window = session.windows[i]; | 164 var window = session.windows[i]; |
165 | |
166 // Show a separator between multiple windows in the same session. | |
167 if (i > 0) | |
168 section.appendChild(doc.createElement('hr')); | |
169 | |
128 for (var j = 0; j < window.tabs.length; j++) { | 170 for (var j = 0; j < window.tabs.length; j++) { |
129 var tab = window.tabs[j]; | 171 var tab = window.tabs[j]; |
130 var a = doc.createElement('a'); | 172 var a = doc.createElement('a'); |
131 a.className = 'footer-menu-item'; | 173 a.className = 'footer-menu-item'; |
132 a.textContent = tab.title; | 174 a.textContent = tab.title; |
133 a.href = tab.url; | 175 a.href = tab.url; |
134 a.style.backgroundImage = 'url(chrome://favicon/' + tab.url + ')'; | 176 a.style.backgroundImage = 'url(chrome://favicon/' + tab.url + ')'; |
135 var clickHandler = this.makeClickHandler_( | 177 var clickHandler = this.makeClickHandler_( |
136 session.tag, String(window.sessionId), String(tab.sessionId)); | 178 session.tag, String(window.sessionId), String(tab.sessionId)); |
137 a.addEventListener('click', clickHandler); | 179 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? | 214 * @param {boolean} signedIn Is the user currently signed in? |
173 */ | 215 */ |
174 updateSignInState: function(signedIn) { | 216 updateSignInState: function(signedIn) { |
175 if (signedIn) | 217 if (signedIn) |
176 chrome.send('getForeignSessions'); | 218 chrome.send('getForeignSessions'); |
177 else | 219 else |
178 this.classList.add('invisible'); | 220 this.classList.add('invisible'); |
179 }, | 221 }, |
180 }; | 222 }; |
181 | 223 |
224 /** | |
225 * Context menu for device names in the list of sessions. | |
226 * This class is designed to be used as a singleton. | |
227 * | |
228 * @constructor | |
229 */ | |
230 function DeviceContextMenu() { | |
Evan Stade
2012/03/30 21:40:58
probably should be called DeviceContextMenuControl
| |
231 this.__proto__ = DeviceContextMenu.prototype; | |
232 this.initialize(); | |
233 } | |
234 cr.addSingletonGetter(DeviceContextMenu); | |
235 | |
236 DeviceContextMenu.prototype = { | |
237 | |
238 initialize: function() { | |
239 var menu = new cr.ui.Menu; | |
240 cr.ui.decorate(menu, cr.ui.Menu); | |
241 menu.classList.add('device-context-menu'); | |
242 menu.classList.add('footer-menu-context-menu'); | |
243 this.menu = menu; | |
244 this.hideItem_ = this.appendMenuItem_('hideSessionMenuItemText'); | |
245 this.hideItem_.addEventListener('activate', this.onHide_.bind(this)); | |
246 }, | |
247 | |
248 /** | |
249 * Appends a menu item to |this.menu|. | |
250 * @param {String} textId The ID for the localized string that acts as | |
251 * the item's label. | |
252 */ | |
253 appendMenuItem_: function(textId) { | |
254 var button = cr.doc.createElement('button'); | |
255 this.menu.appendChild(button); | |
256 cr.ui.decorate(button, cr.ui.MenuItem); | |
257 button.textContent = localStrings.getString(textId); | |
258 return button; | |
259 }, | |
260 | |
261 /** | |
262 * Handler for the 'hide' menu item. | |
263 * @param {Event} e The activation event. | |
264 * @private | |
265 */ | |
266 onHide_: function(e) { | |
267 chrome.send('deleteForeignSession', [this.sessionTag_]); | |
268 chrome.send('getForeignSessions'); // Refresh the list. | |
269 }, | |
270 | |
271 /** | |
272 * Set the session tag which identifies the session that the context menu | |
273 * was invoked on. | |
274 * @param {String} tag The session tag. | |
275 */ | |
276 setSessionTag: function(tag) { | |
277 this.sessionTag_ = tag; | |
278 } | |
279 }; | |
280 | |
182 return { | 281 return { |
183 OtherSessionsMenuButton: OtherSessionsMenuButton, | 282 OtherSessionsMenuButton: OtherSessionsMenuButton, |
184 }; | 283 }; |
185 }); | 284 }); |
OLD | NEW |