1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 * Javascript for local_discovery.html, served from chrome://devices/
7 * This is used to show discoverable devices near the user as well as
8 * cloud devices registered to them.
10 * The object defined in this javascript file listens for callbacks from the
11 * C++ code saying that a new device is available as well as manages the UI for
12 * registering a device on the local network.
15 cr.define('local_discovery', function() {
19 * Prefix for printer management page URLs, relative to base cloud print URL.
22 var PRINTER_MANAGEMENT_PAGE_PREFIX = '#printers/';
24 // Histogram buckets for UMA tracking.
25 /** @const */ var DEVICES_PAGE_EVENTS = {
27 LOG_IN_STARTED_FROM_REGISTER_PROMO: 1,
28 LOG_IN_STARTED_FROM_DEVICE_LIST_PROMO: 2,
29 ADD_PRINTER_CLICKED: 3,
31 REGISTER_CONFIRMED: 5,
36 REGISTER_CANCEL_ON_PRINTER: 10,
42 * Map of service names to corresponding service objects.
43 * @type {Object.<string,Service>}
48 * Whether or not the user is currently logged in.
51 var isUserLoggedIn = true;
54 * Focus manager for page.
56 var focusManager = null;
59 * Object that represents a device in the device list.
60 * @param {Object} info Information about the device.
63 function Device(info, registerEnabled) {
65 this.domElement = null;
66 this.registerButton = null;
67 this.registerEnabled = registerEnabled;
73 * @param {Object} info New information about the device.
75 updateDevice: function(info) {
83 removeDevice: function() {
84 this.deviceContainer().removeChild(this.domElement);
88 * Render the device to the device list.
90 renderDevice: function() {
91 if (this.domElement) {
92 clearElement(this.domElement);
94 this.domElement = document.createElement('div');
95 this.deviceContainer().appendChild(this.domElement);
98 this.registerButton = fillDeviceDescription(
100 this.info.human_readable_name,
101 this.info.description,
102 loadTimeData.getString('serviceRegister'),
103 this.showRegister.bind(this));
105 this.setRegisterEnabled(this.registerEnabled);
109 * Return the correct container for the device.
110 * @param {boolean} is_mine Whether or not the device is in the 'Registered'
113 deviceContainer: function() {
114 return $('register-device-list');
117 * Register the device.
119 register: function() {
120 recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_CONFIRMED);
121 chrome.send('registerDevice', [this.info.service_name]);
122 setRegisterPage('register-page-adding1');
125 * Show registrtation UI for device.
127 showRegister: function() {
128 recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_CLICKED);
129 $('register-message').textContent = loadTimeData.getStringF(
130 'registerConfirmMessage',
131 this.info.human_readable_name);
132 $('register-continue-button').onclick = this.register.bind(this);
133 showRegisterOverlay();
136 * Set registration button enabled/disabled
138 setRegisterEnabled: function(isEnabled) {
139 this.registerEnabled = isEnabled;
140 if (this.registerButton) {
141 this.registerButton.disabled = !isEnabled;
147 * Manages focus for local devices page.
149 * @extends {cr.ui.FocusManager}
151 function LocalDiscoveryFocusManager() {
152 cr.ui.FocusManager.call(this);
153 this.focusParent_ = document.body;
156 LocalDiscoveryFocusManager.prototype = {
157 __proto__: cr.ui.FocusManager.prototype,
159 getFocusParent: function() {
160 return document.querySelector('#overlay .showing') ||
166 * Returns a textual representation of the number of printers on the network.
167 * @return {string} Number of printers on the network as localized string.
169 function generateNumberPrintersAvailableText(numberPrinters) {
170 if (numberPrinters == 0) {
171 return loadTimeData.getString('printersOnNetworkZero');
172 } else if (numberPrinters == 1) {
173 return loadTimeData.getString('printersOnNetworkOne');
175 return loadTimeData.getStringF('printersOnNetworkMultiple',
181 * Fill device element with the description of a device.
182 * @param {HTMLElement} device_dom_element Element to be filled.
183 * @param {string} name Name of device.
184 * @param {string} description Description of device.
185 * @param {string} button_text Text to appear on button.
186 * @param {function()} button_action Action for button.
187 * @return {HTMLElement} The button (for enabling/disabling/rebinding)
189 function fillDeviceDescription(device_dom_element,
194 device_dom_element.classList.add('device');
195 device_dom_element.classList.add('printer');
197 var deviceInfo = document.createElement('div');
198 deviceInfo.className = 'device-info';
199 device_dom_element.appendChild(deviceInfo);
201 var deviceName = document.createElement('h3');
202 deviceName.className = 'device-name';
203 deviceName.textContent = name;
204 deviceInfo.appendChild(deviceName);
206 var deviceDescription = document.createElement('div');
207 deviceDescription.className = 'device-subline';
208 deviceDescription.textContent = description;
209 deviceInfo.appendChild(deviceDescription);
211 var button = document.createElement('button');
212 button.textContent = button_text;
213 button.addEventListener('click', button_action);
214 device_dom_element.appendChild(button);
220 * Show the register overlay.
222 function showRegisterOverlay() {
223 recordUmaEvent(DEVICES_PAGE_EVENTS.ADD_PRINTER_CLICKED);
225 var registerOverlay = $('register-overlay');
226 registerOverlay.classList.add('showing');
227 registerOverlay.focus();
229 $('overlay').hidden = false;
230 setRegisterPage('register-page-confirm');
234 * Hide the register overlay.
236 function hideRegisterOverlay() {
237 $('register-overlay').classList.remove('showing');
238 $('overlay').hidden = true;
242 * Clear a DOM element of all children.
243 * @param {HTMLElement} element DOM element to clear.
245 function clearElement(element) {
246 while (element.firstChild) {
247 element.removeChild(element.firstChild);
252 * Announce that a registration failed.
254 function onRegistrationFailed() {
255 $('error-message').textContent =
256 loadTimeData.getString('addingErrorMessage');
257 setRegisterPage('register-page-error');
258 recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_FAILURE);
262 * Announce that a registration has been canceled on the printer.
264 function onRegistrationCanceledPrinter() {
265 $('error-message').textContent =
266 loadTimeData.getString('addingCanceledMessage');
267 setRegisterPage('register-page-error');
268 recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_CANCEL_ON_PRINTER);
272 * Announce that a registration has timed out.
274 function onRegistrationTimeout() {
275 $('error-message').textContent =
276 loadTimeData.getString('addingTimeoutMessage');
277 setRegisterPage('register-page-error');
278 recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_TIMEOUT);
282 * Update UI to reflect that registration has been confirmed on the printer.
284 function onRegistrationConfirmedOnPrinter() {
285 setRegisterPage('register-page-adding2');
289 * Update device unregistered device list, and update related strings to
290 * reflect the number of devices available to register.
291 * @param {string} name Name of the device.
292 * @param {string} info Additional info of the device or null if the device
295 function onUnregisteredDeviceUpdate(name, info) {
297 if (devices.hasOwnProperty(name)) {
298 devices[name].updateDevice(info);
300 devices[name] = new Device(info, isUserLoggedIn);
301 devices[name].renderDevice();
304 if (devices.hasOwnProperty(name)) {
305 devices[name].removeDevice();
306 delete devices[name];
310 updateUIToReflectState();
314 * Create the DOM for a cloud device described by the device section.
315 * @param {Array.<Object>} devices_list List of devices.
317 function createCloudDeviceDOM(device) {
318 var devicesDomElement = document.createElement('div');
321 if (device.description == '') {
322 description = loadTimeData.getString('noDescription');
324 description = device.description;
327 fillDeviceDescription(devicesDomElement, device.display_name,
328 description, 'Manage' /*Localize*/,
329 manageCloudDevice.bind(null, device.id));
330 return devicesDomElement;
334 * Handle a list of cloud devices available to the user globally.
335 * @param {Array.<Object>} devices_list List of devices.
337 function onCloudDeviceListAvailable(devices_list) {
338 var devicesListLength = devices_list.length;
339 var devicesContainer = $('cloud-devices');
341 clearElement(devicesContainer);
342 $('cloud-devices-loading').hidden = true;
344 for (var i = 0; i < devicesListLength; i++) {
345 devicesContainer.appendChild(createCloudDeviceDOM(devices_list[i]));
350 * Handle the case where the list of cloud devices is not available.
352 function onCloudDeviceListUnavailable() {
353 if (isUserLoggedIn) {
354 $('cloud-devices-loading').hidden = true;
355 $('cloud-devices-unavailable').hidden = false;
360 * Handle the case where the cache for local devices has been flushed..
362 function onDeviceCacheFlushed() {
363 for (var deviceName in devices) {
364 devices[deviceName].removeDevice();
365 delete devices[deviceName];
368 updateUIToReflectState();
372 * Update UI strings to reflect the number of local devices.
374 function updateUIToReflectState() {
375 var numberPrinters = $('register-device-list').children.length;
376 if (numberPrinters == 0) {
377 $('no-printers-message').hidden = false;
379 $('register-login-promo').hidden = true;
381 $('no-printers-message').hidden = true;
382 $('register-login-promo').hidden = isUserLoggedIn;
387 * Announce that a registration succeeeded.
389 function onRegistrationSuccess(device_data) {
390 hideRegisterOverlay();
391 var deviceDOM = createCloudDeviceDOM(device_data);
392 $('cloud-devices').insertBefore(deviceDOM, $('cloud-devices').firstChild);
393 recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_SUCCESS);
397 * Update visibility status for page.
399 function updateVisibility() {
400 chrome.send('isVisible', [!document.webkitHidden]);
404 * Set the page that the register wizard is on.
405 * @param {string} page_id ID string for page.
407 function setRegisterPage(page_id) {
408 var pages = $('register-overlay').querySelectorAll('.register-page');
409 var pagesLength = pages.length;
410 for (var i = 0; i < pagesLength; i++) {
411 pages[i].hidden = true;
414 $(page_id).hidden = false;
418 * Request the printer list.
420 function requestPrinterList() {
421 if (isUserLoggedIn) {
422 clearElement($('cloud-devices'));
423 $('cloud-devices-loading').hidden = false;
424 $('cloud-devices-unavailable').hidden = true;
426 chrome.send('requestPrinterList');
431 * Go to management page for a cloud device.
432 * @param {string} device_id ID of device.
434 function manageCloudDevice(device_id) {
435 recordUmaEvent(DEVICES_PAGE_EVENTS.MANAGE_CLICKED);
436 chrome.send('openCloudPrintURL',
437 [PRINTER_MANAGEMENT_PAGE_PREFIX + device_id]);
441 * Record an event in the UMA histogram.
442 * @param {number} eventId The id of the event to be recorded.
445 function recordUmaEvent(eventId) {
446 chrome.send('metricsHandler:recordInHistogram',
447 ['LocalDiscovery.DevicesPage', eventId, DEVICES_PAGE_EVENTS.MAX_EVENT]);
451 * Cancel the registration.
453 function cancelRegistration() {
454 hideRegisterOverlay();
455 chrome.send('cancelRegistration');
456 recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_CANCEL);
460 * Retry loading the devices from Google Cloud Print.
462 function retryLoadCloudDevices() {
463 requestPrinterList();
467 * User is not logged in.
469 function setUserLoggedIn(userLoggedIn) {
470 isUserLoggedIn = userLoggedIn;
472 $('cloud-devices-login-promo').hidden = isUserLoggedIn;
475 if (isUserLoggedIn) {
476 requestPrinterList();
477 $('register-login-promo').hidden = true;
479 $('cloud-devices-loading').hidden = true;
480 $('cloud-devices-unavailable').hidden = true;
481 clearElement($('cloud-devices'));
484 updateUIToReflectState();
486 for (var device in devices) {
487 devices[device].setRegisterEnabled(isUserLoggedIn);
491 function openSignInPage() {
492 chrome.send('showSyncUI');
495 function registerLoginButtonClicked() {
496 recordUmaEvent(DEVICES_PAGE_EVENTS.LOG_IN_STARTED_FROM_REGISTER_PROMO);
500 function cloudDevicesLoginButtonClicked() {
501 recordUmaEvent(DEVICES_PAGE_EVENTS.LOG_IN_STARTED_FROM_DEVICE_LIST_PROMO);
506 * Set the Cloud Print proxy UI to enabled, disabled, or processing.
509 function setupCloudPrintConnectorSection(disabled, label, allowed) {
510 if (!cr.isChromeOS && !cr.isMac) {
511 $('cloudPrintConnectorLabel').textContent = label;
512 if (disabled || !allowed) {
513 $('cloudPrintConnectorSetupButton').textContent =
514 loadTimeData.getString('cloudPrintConnectorDisabledButton');
516 $('cloudPrintConnectorSetupButton').textContent =
517 loadTimeData.getString('cloudPrintConnectorEnabledButton');
519 $('cloudPrintConnectorSetupButton').disabled = !allowed;
522 $('cloudPrintConnectorSetupButton').onclick = function(event) {
523 // Disable the button, set its text to the intermediate state.
524 $('cloudPrintConnectorSetupButton').textContent =
525 loadTimeData.getString('cloudPrintConnectorEnablingButton');
526 $('cloudPrintConnectorSetupButton').disabled = true;
527 chrome.send('showCloudPrintSetupDialog');
530 $('cloudPrintConnectorSetupButton').onclick = function(event) {
531 chrome.send('disableCloudPrintConnector');
532 requestPrinterList();
538 function removeCloudPrintConnectorSection() {
539 if (!cr.isChromeOS && !cr.isMac) {
540 var connectorSectionElm = $('cloud-print-connector-section');
541 if (connectorSectionElm)
542 connectorSectionElm.parentNode.removeChild(connectorSectionElm);
547 document.addEventListener('DOMContentLoaded', function() {
548 cr.ui.overlay.setupOverlay($('overlay'));
549 cr.ui.overlay.globalInitialization();
550 $('overlay').addEventListener('cancelOverlay', cancelRegistration);
552 var cancelButtons = document.querySelectorAll('.register-cancel');
553 var cancelButtonsLength = cancelButtons.length;
554 for (var i = 0; i < cancelButtonsLength; i++) {
555 cancelButtons[i].addEventListener('click', cancelRegistration);
558 $('register-error-exit').addEventListener('click', cancelRegistration);
561 $('cloud-devices-retry-button').addEventListener('click',
562 retryLoadCloudDevices);
564 $('cloud-devices-login-button').addEventListener(
566 cloudDevicesLoginButtonClicked);
568 $('register-login-button').addEventListener(
570 registerLoginButtonClicked);
573 document.addEventListener('webkitvisibilitychange', updateVisibility,
577 focusManager = new LocalDiscoveryFocusManager();
578 focusManager.initialize();
580 chrome.send('start');
581 recordUmaEvent(DEVICES_PAGE_EVENTS.OPENED);
585 onRegistrationSuccess: onRegistrationSuccess,
586 onRegistrationFailed: onRegistrationFailed,
587 onUnregisteredDeviceUpdate: onUnregisteredDeviceUpdate,
588 onRegistrationConfirmedOnPrinter: onRegistrationConfirmedOnPrinter,
589 onCloudDeviceListAvailable: onCloudDeviceListAvailable,
590 onCloudDeviceListUnavailable: onCloudDeviceListUnavailable,
591 onDeviceCacheFlushed: onDeviceCacheFlushed,
592 onRegistrationCanceledPrinter: onRegistrationCanceledPrinter,
593 onRegistrationTimeout: onRegistrationTimeout,
594 setUserLoggedIn: setUserLoggedIn,
595 setupCloudPrintConnectorSection: setupCloudPrintConnectorSection,
596 removeCloudPrintConnectorSection: removeCloudPrintConnectorSection