| Index: chrome/browser/resources/options2/chromeos/bluetooth_list_element.js
|
| diff --git a/chrome/browser/resources/options2/chromeos/bluetooth_list_element.js b/chrome/browser/resources/options2/chromeos/bluetooth_list_element.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1b6ef82764c55c1cc87f872efc6a4a597cf1c08c
|
| --- /dev/null
|
| +++ b/chrome/browser/resources/options2/chromeos/bluetooth_list_element.js
|
| @@ -0,0 +1,387 @@
|
| +// Copyright (c) 2011 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.
|
| +
|
| +cr.define('options.system.bluetooth', function() {
|
| + /**
|
| + * Bluetooth settings constants.
|
| + */
|
| + function Constants() {}
|
| +
|
| + /**
|
| + * Enumeration of supported device types. Each device type has an
|
| + * associated icon and CSS style.
|
| + * @enum {string}
|
| + */
|
| + Constants.DEVICE_TYPE = {
|
| + COMPUTER: 'computer',
|
| + HEADSET: 'headset',
|
| + KEYBOARD: 'input-keyboard',
|
| + MOUSE: 'input-mouse',
|
| + PHONE: 'phone',
|
| + };
|
| +
|
| + /**
|
| + * Enumeration of possible states for a bluetooth device. The value
|
| + * associated with each state maps to a localized string in the global
|
| + * variable 'templateData'.
|
| + * @enum {string}
|
| + */
|
| + Constants.DEVICE_STATUS = {
|
| + CONNECTED: 'bluetoothDeviceConnected',
|
| + CONNECTING: 'bluetoothDeviceConnecting',
|
| + FAILED_PAIRING: 'bluetoothDeviceFailedPairing',
|
| + NOT_PAIRED: 'bluetoothDeviceNotPaired',
|
| + PAIRED: 'bluetoothDevicePaired'
|
| + };
|
| +
|
| + /**
|
| + * Enumeration of possible states during pairing. The value associated
|
| + * with each state maps to a loalized string in the global variable
|
| + * 'tempateData'.
|
| + * @enum {string}
|
| + */
|
| + Constants.PAIRING = {
|
| + CONFIRM_PASSKEY: 'bluetoothConfirmPasskey',
|
| + ENTER_PASSKEY: 'bluetoothEnterPasskey',
|
| + FAILED_CONNECT_INSTRUCTIONS: 'bluetoothFailedPairingInstructions',
|
| + REMOTE_PASSKEY: 'bluetoothRemotePasskey'
|
| + };
|
| +
|
| + /**
|
| + * Creates an element for storing a list of bluetooth devices.
|
| + * @param {Object=} opt_propertyBag Optional properties.
|
| + * @constructor
|
| + * @extends {HTMLDivElement}
|
| + */
|
| + var BluetoothListElement = cr.ui.define('div');
|
| +
|
| + BluetoothListElement.prototype = {
|
| + __proto__: HTMLDivElement.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + },
|
| +
|
| + /**
|
| + * Loads given list of bluetooth devices. This list will comprise of
|
| + * devices that are currently connected. New devices are discovered
|
| + * via the 'Find devices' button.
|
| + * @param {Array} devices An array of bluetooth devices.
|
| + */
|
| + load: function(devices) {
|
| + this.textContent = '';
|
| + for (var i = 0; i < devices.length; i++) {
|
| + if (this.isSupported_(devices[i]))
|
| + this.appendChild(new BluetoothItem(devices[i]));
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Adds a bluetooth device to the list of available devices. A check is
|
| + * made to see if the device is already in the list, in which case the
|
| + * existing device is updated.
|
| + * @param {Object.<string,string>} device Description of the bluetooth
|
| + * device.
|
| + * @return {boolean} True if the devies was successfully added or updated.
|
| + */
|
| + appendDevice: function(device) {
|
| + if (!this.isSupported_(device))
|
| + return false;
|
| + var item = new BluetoothItem(device);
|
| + var existing = this.findDevice(device.address);
|
| + if (existing)
|
| + this.replaceChild(item, existing);
|
| + else
|
| + this.appendChild(item);
|
| + return true;
|
| + },
|
| +
|
| + /**
|
| + * Scans the list of elements corresponding to discovered Bluetooth
|
| + * devices for one with a matching address.
|
| + * @param {string} address The address of the device.
|
| + * @return {Element|undefined} Element corresponding to the device address
|
| + * or undefined if no corresponding element is found.
|
| + */
|
| + findDevice: function(address) {
|
| + var candidate = this.firstChild;
|
| + while (candidate) {
|
| + if (candidate.data.address == address)
|
| + return candidate;
|
| + candidate = candidate.nextSibling;
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Tests if the bluetooth device is supported based on the type of device.
|
| + * @param {Object.<string,string>} device Desription of the device.
|
| + * @return {boolean} true if the device is supported.
|
| + * @private
|
| + */
|
| + isSupported_: function(device) {
|
| + var target = device.icon;
|
| + for (var key in Constants.DEVICE_TYPE) {
|
| + if (Constants.DEVICE_TYPE[key] == target)
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| + };
|
| +
|
| + /**
|
| + * Creates an element in the list of bluetooth devices.
|
| + * @param {{name: string,
|
| + * address: string,
|
| + * icon: Constants.DEVICE_TYPE,
|
| + * paired: boolean,
|
| + * connected: boolean,
|
| + * pairing: string|undefined,
|
| + * passkey: number|undefined,
|
| + * entered: number|undefined}} device
|
| + * Decription of the bluetooth device.
|
| + * @constructor
|
| + */
|
| + function BluetoothItem(device) {
|
| + var el = $('bluetooth-item-template').cloneNode(true);
|
| + el.__proto__ = BluetoothItem.prototype;
|
| + el.removeAttribute('id');
|
| + el.hidden = false;
|
| + el.data = {};
|
| + for (var key in device)
|
| + el.data[key] = device[key];
|
| + el.decorate();
|
| + return el;
|
| + }
|
| +
|
| + BluetoothItem.prototype = {
|
| + __proto__: HTMLDivElement.prototype,
|
| +
|
| + /** @inheritDoc */
|
| + decorate: function() {
|
| + this.className = 'bluetooth-item';
|
| + this.connected = this.data.connected;
|
| + // Though strictly speaking, a connected device will also be paired,
|
| + // we are interested in tracking paired devices that are not connected.
|
| + this.paired = this.data.paired && !this.data.connected;
|
| + this.connecting = !!this.data.pairing;
|
| + this.addLabels_();
|
| + this.addButtons_();
|
| + },
|
| +
|
| + /**
|
| + * Retrieves the descendent element with the matching class name.
|
| + * @param {string} className The class name for the target element.
|
| + * @return {Element|undefined} Returns the matching element if
|
| + * found and unique.
|
| + * @private
|
| + */
|
| + getNodeByClass_:function(className) {
|
| + var elements = this.getElementsByClassName(className);
|
| + if (elements && elements.length == 1)
|
| + return elements[0];
|
| + },
|
| +
|
| + /**
|
| + * Sets the text content for an element.
|
| + * @param {string} className The class name of the target element.
|
| + * @param {string} label Text content for the element.
|
| + * @private
|
| + */
|
| + setLabel_: function(className, label) {
|
| + var el = this.getNodeByClass_(className);
|
| + el.textContent = label;
|
| + },
|
| +
|
| + /**
|
| + * Adds an element containing the display name, status and device pairing
|
| + * instructions.
|
| + * @private
|
| + */
|
| + addLabels_: function() {
|
| + this.setLabel_('network-name-label', this.data.name);
|
| + var status;
|
| + if (this.data.connected)
|
| + status = Constants.DEVICE_STATUS.CONNECTED;
|
| + else if (this.data.pairing)
|
| + status = Constants.DEVICE_STATUS.CONNECTING;
|
| + if (status) {
|
| + var statusMessage = templateData[status];
|
| + if (statusMessage)
|
| + this.setLabel_('network-status-label', statusMessage);
|
| + if (this.connecting) {
|
| + var spinner = this.getNodeByClass_('inline-spinner');
|
| + spinner.hidden = false;
|
| + }
|
| + }
|
| + if (this.data.pairing)
|
| + this.addPairingInstructions_();
|
| + },
|
| +
|
| + /**
|
| + * Adds instructions on how to complete the pairing process.
|
| + * @param {!Element} textDiv Target element for inserting the instructions.
|
| + * @private
|
| + */
|
| + addPairingInstructions_: function() {
|
| + var instructionsEl = this.getNodeByClass_('bluetooth-instructions');
|
| + var message = templateData[this.data.pairing];
|
| + var array = this.formatInstructions_(message);
|
| + for (var i = 0; i < array.length; i++) {
|
| + instructionsEl.appendChild(array[i]);
|
| + }
|
| + if (this.data.pairing == Constants.PAIRING.ENTER_PASSKEY) {
|
| + var input = this.ownerDocument.createElement('input');
|
| + input.type = 'text';
|
| + input.className = 'bluetooth-passkey-field';
|
| + instructionsEl.appendChild(input);
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Formats the pairing instruction, which may contain labels for
|
| + * substitution. The label '%1' is replaced with the passkey, and '%2'
|
| + * is replaced with the name of the bluetooth device. Formatting of the
|
| + * passkey depends on the type of validation.
|
| + * @param {string} instructions The source instructions to format.
|
| + * @return {Array.<Element>} Array of formatted elements.
|
| + */
|
| + formatInstructions_: function(instructions) {
|
| + var array = [];
|
| + var index = instructions.indexOf('%');
|
| + if (index >= 0) {
|
| + array.push(this.createTextElement_(instructions.substring(0, index)));
|
| + var labelPlaceholder = instructions.charAt(index + 1);
|
| + // ... handle the placeholder
|
| + switch (labelPlaceholder) {
|
| + case '1':
|
| + array.push(this.createPasskeyElement_());
|
| + break;
|
| + case '2':
|
| + array.push(this.createTextElement_(this.data.name));
|
| + }
|
| + array = array.concat(this.formatInstructions_(instructions.substring(
|
| + index + 2)));
|
| + } else {
|
| + array.push(this.createTextElement_(instructions));
|
| + }
|
| + return array;
|
| + },
|
| +
|
| + /**
|
| + * Formats an element for displaying the passkey.
|
| + * @return {Element} Element containing the passkey.
|
| + */
|
| + createPasskeyElement_: function() {
|
| + var passkeyEl = document.createElement('div');
|
| + if (this.data.pairing == Constants.PAIRING.REMOTE_PASSKEY) {
|
| + passkeyEl.className = 'bluetooth-remote-passkey';
|
| + var key = String(this.data.passkey);
|
| + var progress = this.data.entered;
|
| + for (var i = 0; i < key.length; i++) {
|
| + var keyEl = document.createElement('div');
|
| + keyEl.textContent = key.charAt(i);
|
| + keyEl.className = 'bluetooth-passkey-char';
|
| + if (i < progress)
|
| + keyEl.classList.add('key-typed');
|
| + passkeyEl.appendChild(keyEl);
|
| + }
|
| + // Add return key symbol.
|
| + var keyEl = document.createElement('div');
|
| + keyEl.className = 'bluetooth-passkey-char';
|
| + keyEl.textContent = '\u23ce';
|
| + passkeyEl.appendChild(keyEl);
|
| + } else {
|
| + passkeyEl.className = 'bluetooth-confirm-passkey';
|
| + passkeyEl.textContent = this.data.passkey;
|
| + }
|
| + return passkeyEl;
|
| + },
|
| +
|
| + /**
|
| + * Adds a text element.
|
| + * @param {string} text The text content of the new element.
|
| + * @param {string=} opt_style Optional parameter for the CSS class for
|
| + * formatting the text element.
|
| + * @return {Element} Element containing the text.
|
| + */
|
| + createTextElement_: function(text, array, opt_style) {
|
| + var el = this.ownerDocument.createElement('span');
|
| + el.textContent = text;
|
| + if (opt_style)
|
| + el.className = opt_style;
|
| + return el;
|
| + },
|
| +
|
| + /**
|
| + * Adds buttons for updating the connectivity of a device.
|
| + * @private.
|
| + */
|
| + addButtons_: function() {
|
| + var buttonsDiv = this.getNodeByClass_('bluetooth-button-group');
|
| + var buttonLabelKey = null;
|
| + var callbackType = null;
|
| + if (this.connected) {
|
| + buttonLabelKey = 'bluetoothDisconnectDevice';
|
| + callbackType = 'disconnect';
|
| + } else if (this.paired) {
|
| + buttonLabelKey = 'bluetoothForgetDevice';
|
| + callbackType = 'forget';
|
| + } else if (this.connecting) {
|
| + if (this.data.pairing == Constants.PAIRING.CONFIRM_PASSKEY) {
|
| + buttonLabelKey = 'bluetoothRejectPasskey';
|
| + callbackType = 'reject';
|
| + } else {
|
| + buttonLabelKey = 'bluetoothCancel';
|
| + callbackType = 'cancel';
|
| + }
|
| + } else {
|
| + buttonLabelKey = 'bluetoothConnectDevice';
|
| + callbackType = 'connect';
|
| + }
|
| + if (buttonLabelKey && callbackType) {
|
| + var buttonEl = this.ownerDocument.createElement('button');
|
| + buttonEl.textContent = localStrings.getString(buttonLabelKey);
|
| + var self = this;
|
| + var callback = function(e) {
|
| + chrome.send('updateBluetoothDevice',
|
| + [self.data.address, callbackType]);
|
| + }
|
| + buttonEl.addEventListener('click', callback);
|
| + buttonsDiv.appendChild(buttonEl);
|
| + }
|
| + if (this.data.pairing == Constants.PAIRING.CONFIRM_PASSKEY ||
|
| + this.data.pairing == Constants.PAIRING.ENTER_PASSKEY) {
|
| + var buttonEl = this.ownerDocument.createElement('button');
|
| + buttonEl.className = 'accept-pairing-button';
|
| + var msg = this.data.pairing == Constants.PAIRING.CONFIRM_PASSKEY ?
|
| + 'bluetoothAcceptPasskey' : 'bluetoothConnectDevice';
|
| + buttonEl.textContent = localStrings.getString(msg);
|
| + var self = this;
|
| + var callback = function(e) {
|
| + var passkey = self.data.passkey;
|
| + if (self.data.pairing == Constants.PAIRING.ENTER_PASSKEY) {
|
| + var passkeyField = self.getNodeByClass_('bluetooth-passkey-field');
|
| + passkey = passkeyField.value;
|
| + }
|
| + chrome.send('updateBluetoothDevice',
|
| + [self.data.address, 'connect', String(passkey)]);
|
| + }
|
| + buttonEl.addEventListener('click', callback);
|
| + buttonsDiv.insertBefore(buttonEl, buttonsDiv.firstChild);
|
| + }
|
| + this.appendChild(buttonsDiv);
|
| + }
|
| + };
|
| +
|
| + cr.defineProperty(BluetoothItem, 'connected', cr.PropertyKind.BOOL_ATTR);
|
| +
|
| + cr.defineProperty(BluetoothItem, 'paired', cr.PropertyKind.BOOL_ATTR);
|
| +
|
| + cr.defineProperty(BluetoothItem, 'connecting', cr.PropertyKind.BOOL_ATTR);
|
| +
|
| + return {
|
| + Constants: Constants,
|
| + BluetoothListElement: BluetoothListElement
|
| + };
|
| +});
|
|
|