Chromium Code Reviews| 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 |