blob: ecbb4b20fb15fc05cc238f962295fb9cb77de692 [file] [log] [blame]
// Copyright 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.
/**
* Javascript for local_discovery.html, served from chrome://devices/
* This is used to show discoverable devices near the user as well as
* cloud devices registered to them.
*
* The object defined in this javascript file listens for callbacks from the
* C++ code saying that a new device is available as well as manages the UI for
* registering a device on the local network.
*/
cr.define('local_discovery', function() {
'use strict';
/**
* Prefix for printer management page URLs, relative to base cloud print URL.
* @type {string}
*/
var PRINTER_MANAGEMENT_PAGE_PREFIX = '#printers/';
// Histogram buckets for UMA tracking.
/** @const */ var DEVICES_PAGE_EVENTS = {
OPENED: 0,
LOG_IN_STARTED_FROM_REGISTER_PROMO: 1,
LOG_IN_STARTED_FROM_DEVICE_LIST_PROMO: 2,
ADD_PRINTER_CLICKED: 3,
REGISTER_CLICKED: 4,
REGISTER_CONFIRMED: 5,
REGISTER_SUCCESS: 6,
REGISTER_CANCEL: 7,
REGISTER_FAILURE: 8,
MANAGE_CLICKED: 9,
MAX_EVENT: 10,
};
/**
* Map of service names to corresponding service objects.
* @type {Object.<string,Service>}
*/
var devices = {};
/**
* Whether or not the user is currently logged in.
* @type bool
*/
var isUserLoggedIn = true;
/**
* Focus manager for page.
*/
var focusManager = null;
/**
* Object that represents a device in the device list.
* @param {Object} info Information about the device.
* @constructor
*/
function Device(info, registerEnabled) {
this.info = info;
this.domElement = null;
this.registerButton = null;
this.registerEnabled = registerEnabled;
}
Device.prototype = {
/**
* Update the device.
* @param {Object} info New information about the device.
*/
updateDevice: function(info) {
this.info = info;
this.renderDevice();
},
/**
* Delete the device.
*/
removeDevice: function() {
this.deviceContainer().removeChild(this.domElement);
},
/**
* Render the device to the device list.
*/
renderDevice: function() {
if (this.domElement) {
clearElement(this.domElement);
} else {
this.domElement = document.createElement('div');
this.deviceContainer().appendChild(this.domElement);
}
this.registerButton = fillDeviceDescription(
this.domElement,
this.info.human_readable_name,
this.info.description,
loadTimeData.getString('serviceRegister'),
this.showRegister.bind(this));
this.setRegisterEnabled(this.registerEnabled);
},
/**
* Return the correct container for the device.
* @param {boolean} is_mine Whether or not the device is in the 'Registered'
* section.
*/
deviceContainer: function() {
return $('register-device-list');
},
/**
* Register the device.
*/
register: function() {
recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_CONFIRMED);
chrome.send('registerDevice', [this.info.service_name]);
setRegisterPage('register-page-adding1');
},
/**
* Show registrtation UI for device.
*/
showRegister: function() {
recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_CLICKED);
$('register-message').textContent = loadTimeData.getStringF(
'registerConfirmMessage',
this.info.human_readable_name);
$('register-continue-button').onclick = this.register.bind(this);
showRegisterOverlay();
},
/**
* Set registration button enabled/disabled
*/
setRegisterEnabled: function(isEnabled) {
this.registerEnabled = isEnabled;
if (this.registerButton) {
this.registerButton.disabled = !isEnabled;
}
}
};
/**
* Manages focus for local devices page.
* @constructor
* @extends {cr.ui.FocusManager}
*/
function LocalDiscoveryFocusManager() {
cr.ui.FocusManager.call(this);
this.focusParent_ = document.body;
}
LocalDiscoveryFocusManager.prototype = {
__proto__: cr.ui.FocusManager.prototype,
/** @override */
getFocusParent: function() {
return document.querySelector('#overlay .showing') ||
$('main-page');
}
};
/**
* Returns a textual representation of the number of printers on the network.
* @return {string} Number of printers on the network as localized string.
*/
function generateNumberPrintersAvailableText(numberPrinters) {
if (numberPrinters == 0) {
return loadTimeData.getString('printersOnNetworkZero');
} else if (numberPrinters == 1) {
return loadTimeData.getString('printersOnNetworkOne');
} else {
return loadTimeData.getStringF('printersOnNetworkMultiple',
numberPrinters);
}
}
/**
* Fill device element with the description of a device.
* @param {HTMLElement} device_dom_element Element to be filled.
* @param {string} name Name of device.
* @param {string} description Description of device.
* @param {string} button_text Text to appear on button.
* @param {function()} button_action Action for button.
* @return {HTMLElement} The button (for enabling/disabling/rebinding)
*/
function fillDeviceDescription(device_dom_element,
name,
description,
button_text,
button_action) {
device_dom_element.classList.add('device');
device_dom_element.classList.add('printer');
var deviceInfo = document.createElement('div');
deviceInfo.className = 'device-info';
device_dom_element.appendChild(deviceInfo);
var deviceName = document.createElement('h3');
deviceName.className = 'device-name';
deviceName.textContent = name;
deviceInfo.appendChild(deviceName);
var deviceDescription = document.createElement('div');
deviceDescription.className = 'device-subline';
deviceDescription.textContent = description;
deviceInfo.appendChild(deviceDescription);
var button = document.createElement('button');
button.textContent = button_text;
button.addEventListener('click', button_action);
device_dom_element.appendChild(button);
return button;
}
/**
* Show the register overlay.
*/
function showRegisterOverlay() {
recordUmaEvent(DEVICES_PAGE_EVENTS.ADD_PRINTER_CLICKED);
var registerOverlay = $('register-overlay');
registerOverlay.classList.add('showing');
registerOverlay.focus();
$('overlay').hidden = false;
setRegisterPage('register-page-confirm');
}
/**
* Hide the register overlay.
*/
function hideRegisterOverlay() {
$('register-overlay').classList.remove('showing');
$('overlay').hidden = true;
}
/**
* Clear a DOM element of all children.
* @param {HTMLElement} element DOM element to clear.
*/
function clearElement(element) {
while (element.firstChild) {
element.removeChild(element.firstChild);
}
}
/**
* Announce that a registration failed.
*/
function onRegistrationFailed() {
setRegisterPage('register-page-error');
recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_FAILURE);
}
/**
* Update UI to reflect that registration has been confirmed on the printer.
*/
function onRegistrationConfirmedOnPrinter() {
setRegisterPage('register-page-adding2');
}
/**
* Update device unregistered device list, and update related strings to
* reflect the number of devices available to register.
* @param {string} name Name of the device.
* @param {string} info Additional info of the device or null if the device
* has been removed.
*/
function onUnregisteredDeviceUpdate(name, info) {
if (info) {
if (devices.hasOwnProperty(name)) {
devices[name].updateDevice(info);
} else {
devices[name] = new Device(info, isUserLoggedIn);
devices[name].renderDevice();
}
} else {
if (devices.hasOwnProperty(name)) {
devices[name].removeDevice();
delete devices[name];
}
}
updateUIToReflectState();
}
/**
* Handle a list of cloud devices available to the user globally.
* @param {Array.<Object>} devices_list List of devices.
*/
function onCloudDeviceListAvailable(devices_list) {
var devicesListLength = devices_list.length;
var devicesContainer = $('cloud-devices');
clearElement(devicesContainer);
$('cloud-devices-loading').hidden = true;
for (var i = 0; i < devicesListLength; i++) {
var devicesDomElement = document.createElement('div');
devicesContainer.appendChild(devicesDomElement);
var description;
if (devices_list[i].description == '') {
description = loadTimeData.getString('noDescription');
} else {
description = devices_list[i].description;
}
fillDeviceDescription(devicesDomElement, devices_list[i].display_name,
description, 'Manage' /*Localize*/,
manageCloudDevice.bind(null, devices_list[i].id));
}
}
/**
* Handle the case where the list of cloud devices is not available.
*/
function onCloudDeviceListUnavailable() {
if (isUserLoggedIn) {
$('cloud-devices-loading').hidden = true;
$('cloud-devices-unavailable').hidden = false;
}
}
/**
* Handle the case where the cache for local devices has been flushed..
*/
function onDeviceCacheFlushed() {
for (var deviceName in devices) {
devices[deviceName].removeDevice();
delete devices[deviceName];
}
updateUIToReflectState();
}
/**
* Update UI strings to reflect the number of local devices.
*/
function updateUIToReflectState() {
var numberPrinters = $('register-device-list').children.length;
if (numberPrinters == 0) {
$('no-printers-message').hidden = false;
$('register-login-promo').hidden = true;
} else {
$('no-printers-message').hidden = true;
$('register-login-promo').hidden = isUserLoggedIn;
}
}
/**
* Announce that a registration succeeeded.
*/
function onRegistrationSuccess() {
hideRegisterOverlay();
requestPrinterList();
recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_SUCCESS);
}
/**
* Update visibility status for page.
*/
function updateVisibility() {
chrome.send('isVisible', [!document.webkitHidden]);
}
/**
* Set the page that the register wizard is on.
* @param {string} page_id ID string for page.
*/
function setRegisterPage(page_id) {
var pages = $('register-overlay').querySelectorAll('.register-page');
var pagesLength = pages.length;
for (var i = 0; i < pagesLength; i++) {
pages[i].hidden = true;
}
$(page_id).hidden = false;
}
/**
* Request the printer list.
*/
function requestPrinterList() {
if (isUserLoggedIn) {
clearElement($('cloud-devices'));
$('cloud-devices-loading').hidden = false;
$('cloud-devices-unavailable').hidden = true;
chrome.send('requestPrinterList');
}
}
/**
* Go to management page for a cloud device.
* @param {string} device_id ID of device.
*/
function manageCloudDevice(device_id) {
recordUmaEvent(DEVICES_PAGE_EVENTS.MANAGE_CLICKED);
chrome.send('openCloudPrintURL',
[PRINTER_MANAGEMENT_PAGE_PREFIX + device_id]);
}
/**
* 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',
['LocalDiscovery.DevicesPage', eventId, DEVICES_PAGE_EVENTS.MAX_EVENT]);
}
/**
* Cancel the registration.
*/
function cancelRegistration() {
hideRegisterOverlay();
chrome.send('cancelRegistration');
recordUmaEvent(DEVICES_PAGE_EVENTS.REGISTER_CANCEL);
}
/**
* Retry loading the devices from Google Cloud Print.
*/
function retryLoadCloudDevices() {
requestPrinterList();
}
/**
* User is not logged in.
*/
function setUserLoggedIn(userLoggedIn) {
isUserLoggedIn = userLoggedIn;
$('cloud-devices-login-promo').hidden = isUserLoggedIn;
if (isUserLoggedIn) {
requestPrinterList();
$('register-login-promo').hidden = true;
} else {
$('cloud-devices-loading').hidden = true;
$('cloud-devices-unavailable').hidden = true;
}
updateUIToReflectState();
for (var device in devices) {
devices[device].setRegisterEnabled(isUserLoggedIn);
}
}
function openSignInPage() {
chrome.send('showSyncUI');
}
function registerLoginButtonClicked() {
recordUmaEvent(DEVICES_PAGE_EVENTS.LOG_IN_STARTED_FROM_REGISTER_PROMO);
openSignInPage();
}
function cloudDevicesLoginButtonClicked() {
recordUmaEvent(DEVICES_PAGE_EVENTS.LOG_IN_STARTED_FROM_DEVICE_LIST_PROMO);
openSignInPage();
}
/**
* Set the Cloud Print proxy UI to enabled, disabled, or processing.
* @private
*/
function setupCloudPrintConnectorSection(disabled, label, allowed) {
if (!cr.isChromeOS && !cr.isMac) {
$('cloudPrintConnectorLabel').textContent = label;
if (disabled || !allowed) {
$('cloudPrintConnectorSetupButton').textContent =
loadTimeData.getString('cloudPrintConnectorDisabledButton');
} else {
$('cloudPrintConnectorSetupButton').textContent =
loadTimeData.getString('cloudPrintConnectorEnabledButton');
}
$('cloudPrintConnectorSetupButton').disabled = !allowed;
if (disabled) {
$('cloudPrintConnectorSetupButton').onclick = function(event) {
// Disable the button, set its text to the intermediate state.
$('cloudPrintConnectorSetupButton').textContent =
loadTimeData.getString('cloudPrintConnectorEnablingButton');
$('cloudPrintConnectorSetupButton').disabled = true;
chrome.send('showCloudPrintSetupDialog');
};
} else {
$('cloudPrintConnectorSetupButton').onclick = function(event) {
chrome.send('disableCloudPrintConnector');
requestPrinterList();
};
}
}
}
function removeCloudPrintConnectorSection() {
if (!cr.isChromeOS && !cr.isMac) {
var connectorSectionElm = $('cloud-print-connector-section');
if (connectorSectionElm)
connectorSectionElm.parentNode.removeChild(connectorSectionElm);
}
}
document.addEventListener('DOMContentLoaded', function() {
cr.ui.overlay.setupOverlay($('overlay'));
cr.ui.overlay.globalInitialization();
$('overlay').addEventListener('cancelOverlay', cancelRegistration);
var cancelButtons = document.querySelectorAll('.register-cancel');
var cancelButtonsLength = cancelButtons.length;
for (var i = 0; i < cancelButtonsLength; i++) {
cancelButtons[i].addEventListener('click', cancelRegistration);
}
$('register-error-exit').addEventListener('click', cancelRegistration);
$('cloud-devices-retry-button').addEventListener('click',
retryLoadCloudDevices);
$('cloud-devices-login-button').addEventListener(
'click',
cloudDevicesLoginButtonClicked);
$('register-login-button').addEventListener(
'click',
registerLoginButtonClicked);
updateVisibility();
document.addEventListener('webkitvisibilitychange', updateVisibility,
false);
focusManager = new LocalDiscoveryFocusManager();
focusManager.initialize();
chrome.send('start');
recordUmaEvent(DEVICES_PAGE_EVENTS.OPENED);
});
return {
onRegistrationSuccess: onRegistrationSuccess,
onRegistrationFailed: onRegistrationFailed,
onUnregisteredDeviceUpdate: onUnregisteredDeviceUpdate,
onRegistrationConfirmedOnPrinter: onRegistrationConfirmedOnPrinter,
onCloudDeviceListAvailable: onCloudDeviceListAvailable,
onCloudDeviceListUnavailable: onCloudDeviceListUnavailable,
onDeviceCacheFlushed: onDeviceCacheFlushed,
setUserLoggedIn: setUserLoggedIn,
setupCloudPrintConnectorSection: setupCloudPrintConnectorSection,
removeCloudPrintConnectorSection: removeCloudPrintConnectorSection
};
});