| Index: chrome/browser/resources/history/other_devices.js
|
| diff --git a/chrome/browser/resources/history/other_devices.js b/chrome/browser/resources/history/other_devices.js
|
| deleted file mode 100644
|
| index 0a10191e0f7c0728249850012f6034644766c930..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/resources/history/other_devices.js
|
| +++ /dev/null
|
| @@ -1,586 +0,0 @@
|
| -// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -/**
|
| - * @fileoverview The section of the history page that shows tabs from sessions
|
| - on other devices.
|
| - */
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// Globals:
|
| -/** @const */ var MAX_NUM_COLUMNS = 3;
|
| -/** @const */ var NB_ENTRIES_FIRST_ROW_COLUMN = 6;
|
| -/** @const */ var NB_ENTRIES_OTHER_ROWS_COLUMN = 0;
|
| -
|
| -// Histogram buckets for UMA tracking of menu usage.
|
| -/** @const */ var HISTOGRAM_EVENT = {
|
| - INITIALIZED: 0,
|
| - SHOW_MENU: 1,
|
| - LINK_CLICKED: 2,
|
| - LINK_RIGHT_CLICKED: 3,
|
| - SESSION_NAME_RIGHT_CLICKED: 4,
|
| - SHOW_SESSION_MENU: 5,
|
| - COLLAPSE_SESSION: 6,
|
| - EXPAND_SESSION: 7,
|
| - OPEN_ALL: 8,
|
| - HAS_FOREIGN_DATA: 9,
|
| - HIDE_FOR_NOW: 10,
|
| - LIMIT: 11 // Should always be the last one.
|
| -};
|
| -
|
| -/**
|
| - * Record an event in the UMA histogram.
|
| - * @param {number} eventId The id of the event to be recorded.
|
| - * @private
|
| - */
|
| -function recordUmaEvent_(eventId) {
|
| - chrome.send('metricsHandler:recordInHistogram',
|
| - ['HistoryPage.OtherDevicesMenu', eventId, HISTOGRAM_EVENT.LIMIT]);
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// DeviceContextMenuController:
|
| -
|
| -/**
|
| - * Controller for the context menu for device names in the list of sessions.
|
| - * @constructor
|
| - */
|
| -function DeviceContextMenuController() {
|
| - this.__proto__ = DeviceContextMenuController.prototype;
|
| - this.initialize();
|
| -}
|
| -cr.addSingletonGetter(DeviceContextMenuController);
|
| -
|
| -// DeviceContextMenuController, Public: ---------------------------------------
|
| -
|
| -/**
|
| - * Initialize the context menu for device names in the list of sessions.
|
| - */
|
| -DeviceContextMenuController.prototype.initialize = function() {
|
| - var menu = new cr.ui.Menu;
|
| - cr.ui.decorate(menu, cr.ui.Menu);
|
| - this.menu = menu;
|
| - this.collapseItem_ = this.appendMenuItem_('collapseSessionMenuItemText');
|
| - this.collapseItem_.addEventListener('activate',
|
| - this.onCollapseOrExpand_.bind(this));
|
| - this.expandItem_ = this.appendMenuItem_('expandSessionMenuItemText');
|
| - this.expandItem_.addEventListener('activate',
|
| - this.onCollapseOrExpand_.bind(this));
|
| - var openAllItem = this.appendMenuItem_('restoreSessionMenuItemText');
|
| - openAllItem.addEventListener('activate', this.onOpenAll_.bind(this));
|
| - var deleteItem = this.appendMenuItem_('deleteSessionMenuItemText');
|
| - deleteItem.addEventListener('activate', this.onDeleteSession_.bind(this));
|
| -};
|
| -
|
| -/**
|
| - * Set the session data for the session the context menu was invoked on.
|
| - * This should never be called when the menu is visible.
|
| - * @param {Object} session The model object for the session.
|
| - */
|
| -DeviceContextMenuController.prototype.setSession = function(session) {
|
| - this.session_ = session;
|
| - this.updateMenuItems_();
|
| -};
|
| -
|
| -// DeviceContextMenuController, Private: --------------------------------------
|
| -
|
| -/**
|
| - * Appends a menu item to |this.menu|.
|
| - * @param {string} textId The ID for the localized string that acts as
|
| - * the item's label.
|
| - * @return {Element} The button used for a given menu option.
|
| - * @private
|
| - */
|
| -DeviceContextMenuController.prototype.appendMenuItem_ = function(textId) {
|
| - var button = document.createElement('button');
|
| - this.menu.appendChild(button);
|
| - cr.ui.decorate(button, cr.ui.MenuItem);
|
| - button.textContent = loadTimeData.getString(textId);
|
| - return button;
|
| -};
|
| -
|
| -/**
|
| - * Handler for the 'Collapse' and 'Expand' menu items.
|
| - * @param {Event} e The activation event.
|
| - * @private
|
| - */
|
| -DeviceContextMenuController.prototype.onCollapseOrExpand_ = function(e) {
|
| - this.session_.collapsed = !this.session_.collapsed;
|
| - this.updateMenuItems_();
|
| - chrome.send('setForeignSessionCollapsed',
|
| - [this.session_.tag, this.session_.collapsed]);
|
| - chrome.send('getForeignSessions'); // Refresh the list.
|
| -
|
| - var eventId = this.session_.collapsed ?
|
| - HISTOGRAM_EVENT.COLLAPSE_SESSION : HISTOGRAM_EVENT.EXPAND_SESSION;
|
| - recordUmaEvent_(eventId);
|
| -};
|
| -
|
| -/**
|
| - * Handler for the 'Open all' menu item.
|
| - * @param {Event} e The activation event.
|
| - * @private
|
| - */
|
| -DeviceContextMenuController.prototype.onOpenAll_ = function(e) {
|
| - chrome.send('openForeignSession', [this.session_.tag]);
|
| - recordUmaEvent_(HISTOGRAM_EVENT.OPEN_ALL);
|
| -};
|
| -
|
| -/**
|
| - * Handler for the 'Hide for now' menu item.
|
| - * @param {Event} e The activation event.
|
| - * @private
|
| - */
|
| -DeviceContextMenuController.prototype.onDeleteSession_ = function(e) {
|
| - chrome.send('deleteForeignSession', [this.session_.tag]);
|
| - recordUmaEvent_(HISTOGRAM_EVENT.HIDE_FOR_NOW);
|
| -};
|
| -
|
| -/**
|
| - * Set the visibility of the Expand/Collapse menu items based on the state
|
| - * of the session that this menu is currently associated with.
|
| - * @private
|
| - */
|
| -DeviceContextMenuController.prototype.updateMenuItems_ = function() {
|
| - this.collapseItem_.hidden = this.session_.collapsed;
|
| - this.expandItem_.hidden = !this.session_.collapsed;
|
| - this.menu.selectedItem = this.menu.querySelector(':not([hidden])');
|
| -};
|
| -
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// Device:
|
| -
|
| -/**
|
| - * Class to hold all the information about a device entry and generate a DOM
|
| - * node for it.
|
| - * @param {Object} session An object containing the device's session data.
|
| - * @param {DevicesView} view The view object this entry belongs to.
|
| - * @constructor
|
| - */
|
| -function Device(session, view) {
|
| - this.view_ = view;
|
| - this.session_ = session;
|
| - this.searchText_ = view.getSearchText();
|
| -}
|
| -
|
| -// Device, Public: ------------------------------------------------------------
|
| -
|
| -/**
|
| - * Get the DOM node to display this device.
|
| - * @param {int} maxNumTabs The maximum number of tabs to display.
|
| - * @param {int} row The row in which this device is displayed.
|
| - * @return {Object} A DOM node to draw the device.
|
| - */
|
| -Device.prototype.getDOMNode = function(maxNumTabs, row) {
|
| - var deviceDiv = createElementWithClassName('div', 'device');
|
| - this.row_ = row;
|
| - if (!this.session_)
|
| - return deviceDiv;
|
| -
|
| - // Name heading
|
| - var heading = document.createElement('h3');
|
| - var name = heading.appendChild(
|
| - createElementWithClassName('span', 'device-name'));
|
| - name.textContent = this.session_.name;
|
| - heading.sessionData_ = this.session_;
|
| - deviceDiv.appendChild(heading);
|
| -
|
| - // Keep track of the drop down that triggered the menu, so we know
|
| - // which element to apply the command to.
|
| - var session = this.session_;
|
| - function handleDropDownFocus(e) {
|
| - DeviceContextMenuController.getInstance().setSession(session);
|
| - }
|
| - heading.addEventListener('contextmenu', handleDropDownFocus);
|
| -
|
| - var dropDownButton = new cr.ui.ContextMenuButton;
|
| - dropDownButton.tabIndex = 0;
|
| - dropDownButton.classList.add('drop-down');
|
| - dropDownButton.title = loadTimeData.getString('actionMenuDescription');
|
| - dropDownButton.addEventListener('mousedown', function(event) {
|
| - handleDropDownFocus(event);
|
| - // Mousedown handling of cr.ui.MenuButton.handleEvent calls
|
| - // preventDefault, which prevents blur of the focused element. We need to
|
| - // do blur manually.
|
| - document.activeElement.blur();
|
| - });
|
| - dropDownButton.addEventListener('focus', handleDropDownFocus);
|
| - heading.appendChild(dropDownButton);
|
| -
|
| - var timeSpan = createElementWithClassName('div', 'device-timestamp');
|
| - timeSpan.textContent = this.session_.modifiedTime;
|
| - deviceDiv.appendChild(timeSpan);
|
| -
|
| - cr.ui.contextMenuHandler.setContextMenu(
|
| - heading, DeviceContextMenuController.getInstance().menu);
|
| - if (!this.session_.collapsed)
|
| - deviceDiv.appendChild(this.createSessionContents_(maxNumTabs));
|
| -
|
| - return deviceDiv;
|
| -};
|
| -
|
| -/**
|
| - * Marks tabs as hidden or not in our session based on the given searchText.
|
| - * @param {string} searchText The search text used to filter the content.
|
| - */
|
| -Device.prototype.setSearchText = function(searchText) {
|
| - this.searchText_ = searchText.toLowerCase();
|
| - for (var i = 0; i < this.session_.windows.length; i++) {
|
| - var win = this.session_.windows[i];
|
| - var foundMatch = false;
|
| - for (var j = 0; j < win.tabs.length; j++) {
|
| - var tab = win.tabs[j];
|
| - if (tab.title.toLowerCase().indexOf(this.searchText_) != -1) {
|
| - foundMatch = true;
|
| - tab.hidden = false;
|
| - } else {
|
| - tab.hidden = true;
|
| - }
|
| - }
|
| - win.hidden = !foundMatch;
|
| - }
|
| -};
|
| -
|
| -// Device, Private ------------------------------------------------------------
|
| -
|
| -/**
|
| - * Create the DOM tree representing the tabs and windows of this device.
|
| - * @param {int} maxNumTabs The maximum number of tabs to display.
|
| - * @return {Element} A single div containing the list of tabs & windows.
|
| - * @private
|
| - */
|
| -Device.prototype.createSessionContents_ = function(maxNumTabs) {
|
| - var contents = createElementWithClassName('ol', 'device-contents');
|
| -
|
| - var sessionTag = this.session_.tag;
|
| - var numTabsShown = 0;
|
| - var numTabsHidden = 0;
|
| - for (var i = 0; i < this.session_.windows.length; i++) {
|
| - var win = this.session_.windows[i];
|
| - if (win.hidden)
|
| - continue;
|
| -
|
| - // Show a separator between multiple windows in the same session.
|
| - if (i > 0 && numTabsShown < maxNumTabs)
|
| - contents.appendChild(document.createElement('hr'));
|
| -
|
| - for (var j = 0; j < win.tabs.length; j++) {
|
| - var tab = win.tabs[j];
|
| - if (tab.hidden)
|
| - continue;
|
| -
|
| - if (numTabsShown < maxNumTabs) {
|
| - numTabsShown++;
|
| - var a = createElementWithClassName('a', 'device-tab-entry');
|
| - a.href = tab.url;
|
| - a.style.backgroundImage = cr.icon.getFavicon(tab.url);
|
| - this.addHighlightedText_(a, tab.title);
|
| - // Add a tooltip, since it might be ellipsized. The ones that are not
|
| - // necessary will be removed once added to the document, so we can
|
| - // compute sizes.
|
| - a.title = tab.title;
|
| -
|
| - // We need to use this to not lose the ids as we go through other loop
|
| - // turns.
|
| - function makeClickHandler(sessionTag, windowId, tabId) {
|
| - return function(e) {
|
| - if (e.button > 1)
|
| - return; // Ignore buttons other than left and middle.
|
| - recordUmaEvent_(HISTOGRAM_EVENT.LINK_CLICKED);
|
| - chrome.send('openForeignSession', [sessionTag, windowId, tabId,
|
| - e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey]);
|
| - e.preventDefault();
|
| - };
|
| - };
|
| - ['click', 'auxclick'].forEach(function(eventName) {
|
| - a.addEventListener(eventName,
|
| - makeClickHandler(sessionTag,
|
| - String(win.sessionId),
|
| - String(tab.sessionId)));
|
| - });
|
| - var wrapper = createElementWithClassName('div', 'device-tab-wrapper');
|
| - wrapper.appendChild(a);
|
| - contents.appendChild(wrapper);
|
| - } else {
|
| - numTabsHidden++;
|
| - }
|
| - }
|
| - }
|
| -
|
| - if (numTabsHidden > 0) {
|
| - var moreLink = document.createElement('a', 'action-link');
|
| - moreLink.classList.add('device-show-more-tabs');
|
| - moreLink.addEventListener('click', this.view_.increaseRowHeight.bind(
|
| - this.view_, this.row_, numTabsHidden));
|
| - // TODO(jshin): Use plural message formatter when available in JS.
|
| - moreLink.textContent = loadTimeData.getStringF('xMore',
|
| - numTabsHidden.toLocaleString());
|
| - var moreWrapper = createElementWithClassName('div', 'more-wrapper');
|
| - moreWrapper.appendChild(moreLink);
|
| - contents.appendChild(moreWrapper);
|
| - }
|
| -
|
| - return contents;
|
| -};
|
| -
|
| -/**
|
| - * Add child text nodes to a node such that occurrences of this.searchText_ are
|
| - * highlighted.
|
| - * @param {Node} node The node under which new text nodes will be made as
|
| - * children.
|
| - * @param {string} content Text to be added beneath |node| as one or more
|
| - * text nodes.
|
| - * @private
|
| - */
|
| -Device.prototype.addHighlightedText_ = function(node, content) {
|
| - var endOfPreviousMatch = 0;
|
| - if (this.searchText_) {
|
| - var lowerContent = content.toLowerCase();
|
| - var searchTextLenght = this.searchText_.length;
|
| - var newMatch = lowerContent.indexOf(this.searchText_, 0);
|
| - while (newMatch != -1) {
|
| - if (newMatch > endOfPreviousMatch) {
|
| - node.appendChild(document.createTextNode(
|
| - content.slice(endOfPreviousMatch, newMatch)));
|
| - }
|
| - endOfPreviousMatch = newMatch + searchTextLenght;
|
| - // Mark the highlighted text in bold.
|
| - var b = document.createElement('b');
|
| - b.textContent = content.substring(newMatch, endOfPreviousMatch);
|
| - node.appendChild(b);
|
| - newMatch = lowerContent.indexOf(this.searchText_, endOfPreviousMatch);
|
| - }
|
| - }
|
| - if (endOfPreviousMatch < content.length) {
|
| - node.appendChild(document.createTextNode(
|
| - content.slice(endOfPreviousMatch)));
|
| - }
|
| -};
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// DevicesView:
|
| -
|
| -/**
|
| - * Functions and state for populating the page with HTML.
|
| - * @constructor
|
| - */
|
| -function DevicesView() {
|
| - this.devices_ = []; // List of individual devices.
|
| - this.resultDiv_ = $('other-devices');
|
| - this.searchText_ = '';
|
| - this.rowHeights_ = [NB_ENTRIES_FIRST_ROW_COLUMN];
|
| - this.focusGrids_ = [];
|
| - this.updateSignInState(loadTimeData.getBoolean('isUserSignedIn'));
|
| - this.hasSeenForeignData_ = false;
|
| - recordUmaEvent_(HISTOGRAM_EVENT.INITIALIZED);
|
| -}
|
| -
|
| -// DevicesView, public: -------------------------------------------------------
|
| -
|
| -/**
|
| - * Updates our sign in state by clearing the view is not signed in or sending
|
| - * a request to get the data to display otherwise.
|
| - * @param {boolean} signedIn Whether the user is signed in or not.
|
| - */
|
| -DevicesView.prototype.updateSignInState = function(signedIn) {
|
| - if (signedIn)
|
| - chrome.send('getForeignSessions');
|
| - else
|
| - this.clearDOM();
|
| -};
|
| -
|
| -/**
|
| - * Resets the view sessions.
|
| - * @param {Object} sessionList The sessions to add.
|
| - */
|
| -DevicesView.prototype.setSessionList = function(sessionList) {
|
| - this.devices_ = [];
|
| - for (var i = 0; i < sessionList.length; i++)
|
| - this.devices_.push(new Device(sessionList[i], this));
|
| - this.displayResults_();
|
| -
|
| - // This metric should only be emitted if we see foreign data, and it should
|
| - // only be emitted once per page refresh. Flip flag to remember because this
|
| - // method is called upon any update.
|
| - if (!this.hasSeenForeignData_ && sessionList.length > 0) {
|
| - this.hasSeenForeignData_ = true;
|
| - recordUmaEvent_(HISTOGRAM_EVENT.HAS_FOREIGN_DATA);
|
| - }
|
| -};
|
| -
|
| -
|
| -/**
|
| - * Sets the current search text.
|
| - * @param {string} searchText The text to search.
|
| - */
|
| -DevicesView.prototype.setSearchText = function(searchText) {
|
| - if (this.searchText_ != searchText) {
|
| - this.searchText_ = searchText;
|
| - for (var i = 0; i < this.devices_.length; i++)
|
| - this.devices_[i].setSearchText(searchText);
|
| - this.displayResults_();
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * @return {string} The current search text.
|
| - */
|
| -DevicesView.prototype.getSearchText = function() {
|
| - return this.searchText_;
|
| -};
|
| -
|
| -/**
|
| - * Clears the DOM content of the view.
|
| - */
|
| -DevicesView.prototype.clearDOM = function() {
|
| - while (this.resultDiv_.hasChildNodes()) {
|
| - this.resultDiv_.removeChild(this.resultDiv_.lastChild);
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Increase the height of a row by the given amount.
|
| - * @param {int} row The row number.
|
| - * @param {int} height The extra height to add to the givent row.
|
| - */
|
| -DevicesView.prototype.increaseRowHeight = function(row, height) {
|
| - for (var i = this.rowHeights_.length; i <= row; i++)
|
| - this.rowHeights_.push(NB_ENTRIES_OTHER_ROWS_COLUMN);
|
| - this.rowHeights_[row] += height;
|
| - this.displayResults_();
|
| -};
|
| -
|
| -// DevicesView, Private -------------------------------------------------------
|
| -
|
| -/**
|
| - * @param {!Element} root
|
| - * @param {?Node} boundary
|
| - * @constructor
|
| - * @extends {cr.ui.FocusRow}
|
| - */
|
| -function DevicesViewFocusRow(root, boundary) {
|
| - cr.ui.FocusRow.call(this, root, boundary);
|
| - assert(this.addItem('menu-button', 'button.drop-down') ||
|
| - this.addItem('device-tab', '.device-tab-entry') ||
|
| - this.addItem('more-tabs', '.device-show-more-tabs'));
|
| -}
|
| -
|
| -DevicesViewFocusRow.prototype = {__proto__: cr.ui.FocusRow.prototype};
|
| -
|
| -/**
|
| - * Update the page with results.
|
| - * @private
|
| - */
|
| -DevicesView.prototype.displayResults_ = function() {
|
| - this.clearDOM();
|
| - var resultsFragment = document.createDocumentFragment();
|
| - if (this.devices_.length == 0)
|
| - return;
|
| -
|
| - // We'll increase to 0 as we create the first row.
|
| - var rowIndex = -1;
|
| - // We need to access the last row and device when we get out of the loop.
|
| - var currentRowElement;
|
| - // This is only set when changing rows, yet used on all device columns.
|
| - var maxNumTabs;
|
| - for (var i = 0; i < this.devices_.length; i++) {
|
| - var device = this.devices_[i];
|
| - // Should we start a new row?
|
| - if (i % MAX_NUM_COLUMNS == 0) {
|
| - if (currentRowElement)
|
| - resultsFragment.appendChild(currentRowElement);
|
| - currentRowElement = createElementWithClassName('div', 'device-row');
|
| - rowIndex++;
|
| - if (rowIndex < this.rowHeights_.length)
|
| - maxNumTabs = this.rowHeights_[rowIndex];
|
| - else
|
| - maxNumTabs = 0;
|
| - }
|
| -
|
| - currentRowElement.appendChild(device.getDOMNode(maxNumTabs, rowIndex));
|
| - }
|
| - if (currentRowElement)
|
| - resultsFragment.appendChild(currentRowElement);
|
| -
|
| - this.resultDiv_.appendChild(resultsFragment);
|
| - // Remove the tootltip on all lines that don't need it. It's easier to
|
| - // remove them here, after adding them all above, since we have the data
|
| - // handy above, but we don't have the width yet. Whereas here, we have the
|
| - // width, and the nodeValue could contain sub nodes for highlighting, which
|
| - // makes it harder to extract the text data here.
|
| - tabs = document.getElementsByClassName('device-tab-entry');
|
| - for (var i = 0; i < tabs.length; i++) {
|
| - if (tabs[i].scrollWidth <= tabs[i].clientWidth)
|
| - tabs[i].title = '';
|
| - }
|
| -
|
| - this.resultDiv_.appendChild(
|
| - createElementWithClassName('div', 'other-devices-bottom'));
|
| -
|
| - this.focusGrids_.forEach(function(grid) { grid.destroy(); });
|
| - this.focusGrids_.length = 0;
|
| -
|
| - var devices = this.resultDiv_.querySelectorAll('.device-contents');
|
| - for (var i = 0; i < devices.length; ++i) {
|
| - var rows = devices[i].querySelectorAll(
|
| - 'h3, .device-tab-wrapper, .more-wrapper');
|
| - if (!rows.length)
|
| - continue;
|
| -
|
| - var grid = new cr.ui.FocusGrid();
|
| - for (var j = 0; j < rows.length; ++j) {
|
| - grid.addRow(new DevicesViewFocusRow(rows[j], devices[i]));
|
| - }
|
| - grid.ensureRowActive();
|
| - this.focusGrids_.push(grid);
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Sets the menu model data. An empty list means that either there are no
|
| - * foreign sessions, or tab sync is disabled for this profile.
|
| - *
|
| - * @param {Array} sessionList Array of objects describing the sessions
|
| - * from other devices.
|
| - */
|
| -function setForeignSessions(sessionList) {
|
| - devicesView.setSessionList(sessionList);
|
| -}
|
| -
|
| -/**
|
| - * Called when initialized or the user's signed in state changes,
|
| - * @param {boolean} isUserSignedIn Is the user currently signed in?
|
| - */
|
| -function updateSignInState(isUserSignedIn) {
|
| - if (devicesView)
|
| - devicesView.updateSignInState(isUserSignedIn);
|
| -}
|
| -
|
| -///////////////////////////////////////////////////////////////////////////////
|
| -// Document Functions:
|
| -/**
|
| - * Window onload handler, sets up the other devices view.
|
| - */
|
| -function load() {
|
| - if (!loadTimeData.getBoolean('isInstantExtendedApiEnabled'))
|
| - return;
|
| -
|
| - devicesView = new DevicesView();
|
| -
|
| - // Create the context menu that appears when the user right clicks
|
| - // on a device name or hit click on the button besides the device name
|
| - document.body.appendChild(DeviceContextMenuController.getInstance().menu);
|
| -
|
| - var doSearch = function(e) {
|
| - devicesView.setSearchText($('search-field').value);
|
| - };
|
| - $('search-field').addEventListener('search', doSearch);
|
| - $('search-button').addEventListener('click', doSearch);
|
| -
|
| - chrome.send('otherDevicesInitialized');
|
| -}
|
| -
|
| -// Add handlers to HTML elements.
|
| -document.addEventListener('DOMContentLoaded', load);
|
|
|