12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @fileoverview The section of the history page that shows tabs from sessions
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 on other devices.
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Globals:
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** @const */ var MAX_NUM_COLUMNS = 3;
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** @const */ var NB_ENTRIES_FIRST_ROW_COLUMN = 6;
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** @const */ var NB_ENTRIES_OTHER_ROWS_COLUMN = 0;
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Histogram buckets for UMA tracking of menu usage.
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Using the same values as the Other Devices button in the NTP.
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** @const */ var HISTOGRAM_EVENT = {
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  INITIALIZED: 0,
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SHOW_MENU: 1,
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LINK_CLICKED: 2,
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LINK_RIGHT_CLICKED: 3,
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SESSION_NAME_RIGHT_CLICKED: 4,
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SHOW_SESSION_MENU: 5,
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  COLLAPSE_SESSION: 6,
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPAND_SESSION: 7,
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OPEN_ALL: 8,
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LIMIT: 9  // Should always be the last one.
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Record an event in the UMA histogram.
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {number} eventId The id of the event to be recorded.
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function recordUmaEvent_(eventId) {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome.send('metricsHandler:recordInHistogram',
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ['HistoryPage.OtherDevicesMenu', eventId, HISTOGRAM_EVENT.LIMIT]);
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DeviceContextMenuController:
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Controller for the context menu for device names in the list of sessions.
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * This class is designed to be used as a singleton. Also copied from existing
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * other devices button in NTP.
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * TODO(mad): Should we extract/reuse/share with ntp4/other_sessions.js?
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function DeviceContextMenuController() {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.__proto__ = DeviceContextMenuController.prototype;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.initialize();
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)cr.addSingletonGetter(DeviceContextMenuController);
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DeviceContextMenuController, Public: ---------------------------------------
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Initialize the context menu for device names in the list of sessions.
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeviceContextMenuController.prototype.initialize = function() {
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var menu = new cr.ui.Menu;
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cr.ui.decorate(menu, cr.ui.Menu);
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.menu = menu;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.collapseItem_ = this.appendMenuItem_('collapseSessionMenuItemText');
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.collapseItem_.addEventListener('activate',
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                      this.onCollapseOrExpand_.bind(this));
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.expandItem_ = this.appendMenuItem_('expandSessionMenuItemText');
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.expandItem_.addEventListener('activate',
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                    this.onCollapseOrExpand_.bind(this));
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.openAllItem_ = this.appendMenuItem_('restoreSessionMenuItemText');
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.openAllItem_.addEventListener('activate',
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     this.onOpenAll_.bind(this));
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Set the session data for the session the context menu was invoked on.
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * This should never be called when the menu is visible.
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} session The model object for the session.
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeviceContextMenuController.prototype.setSession = function(session) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.session_ = session;
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.updateMenuItems_();
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DeviceContextMenuController, Private: --------------------------------------
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Appends a menu item to |this.menu|.
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string} textId The ID for the localized string that acts as
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *     the item's label.
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {Element} The button used for a given menu option.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeviceContextMenuController.prototype.appendMenuItem_ = function(textId) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var button = document.createElement('button');
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.menu.appendChild(button);
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cr.ui.decorate(button, cr.ui.MenuItem);
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  button.textContent = loadTimeData.getString(textId);
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return button;
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Handler for the 'Collapse' and 'Expand' menu items.
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Event} e The activation event.
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeviceContextMenuController.prototype.onCollapseOrExpand_ = function(e) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.session_.collapsed = !this.session_.collapsed;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.updateMenuItems_();
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome.send('setForeignSessionCollapsed',
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              [this.session_.tag, this.session_.collapsed]);
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome.send('getForeignSessions');  // Refresh the list.
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var eventId = this.session_.collapsed ?
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      HISTOGRAM_EVENT.COLLAPSE_SESSION : HISTOGRAM_EVENT.EXPAND_SESSION;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  recordUmaEvent_(eventId);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Handler for the 'Open all' menu item.
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Event} e The activation event.
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeviceContextMenuController.prototype.onOpenAll_ = function(e) {
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  chrome.send('openForeignSession', [this.session_.tag]);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  recordUmaEvent_(HISTOGRAM_EVENT.OPEN_ALL);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Set the visibility of the Expand/Collapse menu items based on the state
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * of the session that this menu is currently associated with.
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DeviceContextMenuController.prototype.updateMenuItems_ = function() {
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.collapseItem_.hidden = this.session_.collapsed;
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.expandItem_.hidden = !this.session_.collapsed;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Device:
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Class to hold all the information about a device entry and generate a DOM
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * node for it.
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} session An object containing the device's session data.
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {DevicesView} view The view object this entry belongs to.
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function Device(session, view) {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.view_ = view;
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.session_ = session;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.searchText_ = view.getSearchText();
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Device, Public: ------------------------------------------------------------
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Get the DOM node to display this device.
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {int} maxNumTabs The maximum number of tabs to display.
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {int} row The row in which this device is displayed.
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {Object} A DOM node to draw the device.
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Device.prototype.getDOMNode = function(maxNumTabs, row) {
1682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var deviceDiv = createElementWithClassName('div', 'device');
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.row_ = row;
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!this.session_)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return deviceDiv;
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Name heading
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var heading = document.createElement('h3');
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heading.textContent = this.session_.name;
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heading.sessionData_ = this.session_;
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  deviceDiv.appendChild(heading);
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Keep track of the drop down that triggered the menu, so we know
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // which element to apply the command to.
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var session = this.session_;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  function handleDropDownFocus(e) {
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DeviceContextMenuController.getInstance().setSession(session);
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heading.addEventListener('contextmenu', handleDropDownFocus);
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var dropDownButton = new cr.ui.ContextMenuButton;
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dropDownButton.classList.add('drop-down');
189c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  dropDownButton.addEventListener('mousedown', function(event) {
190c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      handleDropDownFocus(event);
191c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // Mousedown handling of cr.ui.MenuButton.handleEvent calls
192c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // preventDefault, which prevents blur of the focused element. We need to
193c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      // do blur manually.
194c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      document.activeElement.blur();
195c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  });
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  dropDownButton.addEventListener('focus', handleDropDownFocus);
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heading.appendChild(dropDownButton);
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var timeSpan = createElementWithClassName('div', 'device-timestamp');
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  timeSpan.textContent = this.session_.modifiedTime;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  heading.appendChild(timeSpan);
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  cr.ui.contextMenuHandler.setContextMenu(
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      heading, DeviceContextMenuController.getInstance().menu);
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!this.session_.collapsed)
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    deviceDiv.appendChild(this.createSessionContents_(maxNumTabs));
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return deviceDiv;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Marks tabs as hidden or not in our session based on the given searchText.
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string} searchText The search text used to filter the content.
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Device.prototype.setSearchText = function(searchText) {
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.searchText_ = searchText.toLowerCase();
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < this.session_.windows.length; i++) {
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var win = this.session_.windows[i];
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var foundMatch = false;
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (var j = 0; j < win.tabs.length; j++) {
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      var tab = win.tabs[j];
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (tab.title.toLowerCase().indexOf(this.searchText_) != -1) {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        foundMatch = true;
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        tab.hidden = false;
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        tab.hidden = true;
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    win.hidden = !foundMatch;
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Device, Private ------------------------------------------------------------
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Create the DOM tree representing the tabs and windows of this device.
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {int} maxNumTabs The maximum number of tabs to display.
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {Element} A single div containing the list of tabs & windows.
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
2412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Device.prototype.createSessionContents_ = function(maxNumTabs) {
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var contents = createElementWithClassName('div', 'device-contents');
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var sessionTag = this.session_.tag;
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var numTabsShown = 0;
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var numTabsHidden = 0;
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < this.session_.windows.length; i++) {
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var win = this.session_.windows[i];
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (win.hidden)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      continue;
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Show a separator between multiple windows in the same session.
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i > 0 && numTabsShown < maxNumTabs)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      contents.appendChild(document.createElement('hr'));
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (var j = 0; j < win.tabs.length; j++) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      var tab = win.tabs[j];
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (tab.hidden)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        continue;
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (numTabsShown < maxNumTabs) {
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        numTabsShown++;
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        var a = createElementWithClassName('a', 'device-tab-entry');
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        a.href = tab.url;
265d3868032626d59662ff73b372b5d584c1d144c53Ben Murdoch        a.style.backgroundImage = getFaviconImageSet(tab.url);
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this.addHighlightedText_(a, tab.title);
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Add a tooltip, since it might be ellipsized. The ones that are not
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // necessary will be removed once added to the document, so we can
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // compute sizes.
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        a.title = tab.title;
271c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
272c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // We need to use this to not lose the ids as we go through other loop
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        // turns.
274c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        function makeClickHandler(sessionTag, windowId, tabId) {
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          return function(e) {
276c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            recordUmaEvent_(HISTOGRAM_EVENT.LINK_CLICKED);
277c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            chrome.send('openForeignSession', [sessionTag, windowId, tabId,
278c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey]);
279c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            e.preventDefault();
280c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)          };
281c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        };
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        a.addEventListener('click', makeClickHandler(sessionTag,
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     String(win.sessionId),
284c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                     String(tab.sessionId)));
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        contents.appendChild(a);
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      } else {
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        numTabsHidden++;
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (numTabsHidden > 0) {
293868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    var moreLinkButton = createElementWithClassName('button',
294868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        'device-show-more-tabs link-button');
295868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    moreLinkButton.addEventListener('click', this.view_.increaseRowHeight.bind(
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        this.view_, this.row_, numTabsHidden));
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var xMore = loadTimeData.getString('xMore');
298868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    moreLinkButton.appendChild(
299868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        document.createTextNode(xMore.replace('$1', numTabsHidden)));
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    contents.appendChild(moreLinkButton);
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return contents;
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Add child text nodes to a node such that occurrences of this.searchText_ are
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * highlighted.
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Node} node The node under which new text nodes will be made as
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *     children.
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string} content Text to be added beneath |node| as one or more
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *     text nodes.
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Device.prototype.addHighlightedText_ = function(node, content) {
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var endOfPreviousMatch = 0;
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (this.searchText_) {
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var lowerContent = content.toLowerCase();
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var searchTextLenght = this.searchText_.length;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var newMatch = lowerContent.indexOf(this.searchText_, 0);
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    while (newMatch != -1) {
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (newMatch > endOfPreviousMatch) {
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        node.appendChild(document.createTextNode(
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            content.slice(endOfPreviousMatch, newMatch)));
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      endOfPreviousMatch = newMatch + searchTextLenght;
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Mark the highlighted text in bold.
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      var b = document.createElement('b');
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      b.textContent = content.substring(newMatch, endOfPreviousMatch);
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      node.appendChild(b);
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      newMatch = lowerContent.indexOf(this.searchText_, endOfPreviousMatch);
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (endOfPreviousMatch < content.length) {
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    node.appendChild(document.createTextNode(
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        content.slice(endOfPreviousMatch)));
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DevicesView:
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Functions and state for populating the page with HTML.
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @constructor
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function DevicesView() {
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.devices_ = [];  // List of individual devices.
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.resultDiv_ = $('other-devices');
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.searchText_ = '';
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.rowHeights_ = [NB_ENTRIES_FIRST_ROW_COLUMN];
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.updateSignInState(loadTimeData.getBoolean('isUserSignedIn'));
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  recordUmaEvent_(HISTOGRAM_EVENT.INITIALIZED);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DevicesView, public: -------------------------------------------------------
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Updates our sign in state by clearing the view is not signed in or sending
3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * a request to get the data to display otherwise.
3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {boolean} signedIn Whether the user is signed in or not.
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevicesView.prototype.updateSignInState = function(signedIn) {
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (signedIn)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    chrome.send('getForeignSessions');
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  else
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.clearDOM();
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Resets the view sessions.
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {Object} sessionList The sessions to add.
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevicesView.prototype.setSessionList = function(sessionList) {
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.devices_ = [];
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < sessionList.length; i++)
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.devices_.push(new Device(sessionList[i], this));
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.displayResults_();
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Sets the current search text.
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {string} searchText The text to search.
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevicesView.prototype.setSearchText = function(searchText) {
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (this.searchText_ != searchText) {
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.searchText_ = searchText;
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (var i = 0; i < this.devices_.length; i++)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      this.devices_[i].setSearchText(searchText);
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.displayResults_();
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @return {string} The current search text.
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevicesView.prototype.getSearchText = function() {
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return this.searchText_;
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Clears the DOM content of the view.
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevicesView.prototype.clearDOM = function() {
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  while (this.resultDiv_.hasChildNodes()) {
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.resultDiv_.removeChild(this.resultDiv_.lastChild);
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Increase the height of a row by the given amount.
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {int} row The row number.
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @param {int} height The extra height to add to the givent row.
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevicesView.prototype.increaseRowHeight = function(row, height) {
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = this.rowHeights_.length; i <= row; i++)
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    this.rowHeights_.push(NB_ENTRIES_OTHER_ROWS_COLUMN);
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.rowHeights_[row] += height;
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.displayResults_();
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// DevicesView, Private -------------------------------------------------------
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Update the page with results.
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * @private
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)DevicesView.prototype.displayResults_ = function() {
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.clearDOM();
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var resultsFragment = document.createDocumentFragment();
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (this.devices_.length == 0)
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We'll increase to 0 as we create the first row.
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var rowIndex = -1;
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We need to access the last row and device when we get out of the loop.
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var currentRowElement;
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This is only set when changing rows, yet used on all device columns.
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var maxNumTabs;
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < this.devices_.length; i++) {
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    var device = this.devices_[i];
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Should we start a new row?
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (i % MAX_NUM_COLUMNS == 0) {
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (currentRowElement)
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        resultsFragment.appendChild(currentRowElement);
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      currentRowElement = createElementWithClassName('div', 'devices-row');
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      rowIndex++;
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (rowIndex < this.rowHeights_.length)
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        maxNumTabs = this.rowHeights_[rowIndex];
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      else
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        maxNumTabs = 0;
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    currentRowElement.appendChild(device.getDOMNode(maxNumTabs, rowIndex));
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (currentRowElement)
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    resultsFragment.appendChild(currentRowElement);
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.resultDiv_.appendChild(resultsFragment);
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Remove the tootltip on all lines that don't need it. It's easier to
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // remove them here, after adding them all above, since we have the data
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // handy above, but we don't have the width yet. Whereas here, we have the
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // width, and the nodeValue could contain sub nodes for highlighting, which
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // makes it harder to extract the text data here.
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  tabs = document.getElementsByClassName('device-tab-entry');
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (var i = 0; i < tabs.length; i++) {
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (tabs[i].scrollWidth <= tabs[i].clientWidth)
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      tabs[i].title = '';
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  this.resultDiv_.appendChild(
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      createElementWithClassName('div', 'other-devices-bottom'));
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
476558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch/**
477558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * Sets the menu model data. An empty list means that either there are no
478558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * foreign sessions, or tab sync is disabled for this profile.
479558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * |isTabSyncEnabled| makes it possible to distinguish between the cases.
480558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch *
481558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param {Array} sessionList Array of objects describing the sessions
482558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch *     from other devices.
483558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param {boolean} isTabSyncEnabled Is tab sync enabled for this profile?
484558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch */
485558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochfunction setForeignSessions(sessionList, isTabSyncEnabled) {
486558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // The other devices is shown iff tab sync is enabled.
487558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (isTabSyncEnabled)
488558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    devicesView.setSessionList(sessionList);
489558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  else
490558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    devicesView.clearDOM();
491558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
493558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch/**
494558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * Called when this element is initialized, and from the new tab page when
495558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * the user's signed in state changes,
496558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param {string} header The first line of text (unused here).
497558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param {string} subHeader The second line of text (unused here).
498558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param {string} iconURL The url for the login status icon. If this is null
499558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch then the login status icon is hidden (unused here).
500558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch * @param {boolean} isUserSignedIn Is the user currently signed in?
501558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch */
502558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochfunction updateLogin(header, subHeader, iconURL, isUserSignedIn) {
503558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (devicesView)
504558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    devicesView.updateSignInState(isUserSignedIn);
505558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch}
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
5082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Document Functions:
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/**
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Window onload handler, sets up the other devices view.
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)function load() {
513558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!loadTimeData.getBoolean('isInstantExtendedApiEnabled'))
514558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return;
515558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
516558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // We must use this namespace to reuse the handler code for foreign session
517558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  // and login.
518558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  cr.define('ntp', function() {
519558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return {
520558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      setForeignSessions: setForeignSessions,
521558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      updateLogin: updateLogin
522558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    };
523558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  });
524558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  devicesView = new DevicesView();
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Create the context menu that appears when the user right clicks
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // on a device name or hit click on the button besides the device name
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  document.body.appendChild(DeviceContextMenuController.getInstance().menu);
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  var doSearch = function(e) {
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    devicesView.setSearchText($('search-field').value);
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  };
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  $('search-field').addEventListener('search', doSearch);
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  $('search-button').addEventListener('click', doSearch);
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Add handlers to HTML elements.
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)document.addEventListener('DOMContentLoaded', load);
540