1 // Copyright (c) 2011 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. 4 5 cr.define('options.internet', function() { 6 7 /** 8 * Network settings constants. These enums usually match their C++ 9 * counterparts. 10 */ 11 function Constants() {} 12 // Minimum length for wireless network password. 13 Constants.MIN_WIRELESS_PASSWORD_LENGTH = 5; 14 // Minimum length for SSID name. 15 Constants.MIN_WIRELESS_SSID_LENGTH = 1; 16 // Cellular activation states: 17 Constants.ACTIVATION_STATE_UNKNOWN = 0; 18 Constants.ACTIVATION_STATE_ACTIVATED = 1; 19 Constants.ACTIVATION_STATE_ACTIVATING = 2; 20 Constants.ACTIVATION_STATE_NOT_ACTIVATED = 3; 21 Constants.ACTIVATION_STATE_PARTIALLY_ACTIVATED = 4; 22 // Network types: 23 Constants.TYPE_UNKNOWN = 0; 24 Constants.TYPE_ETHERNET = 1; 25 Constants.TYPE_WIFI = 2; 26 Constants.TYPE_WIMAX = 3; 27 Constants.TYPE_BLUETOOTH = 4; 28 Constants.TYPE_CELLULAR = 5; 29 30 /** 31 * Creates a new network list div. 32 * @param {Object=} opt_propertyBag Optional properties. 33 * @constructor 34 * @extends {HTMLDivElement} 35 */ 36 var NetworkElement = cr.ui.define('div'); 37 38 NetworkElement.prototype = { 39 __proto__: HTMLDivElement.prototype, 40 41 /** @inheritDoc */ 42 decorate: function() { 43 this.addEventListener('click', this.handleClick_); 44 }, 45 46 /** 47 * Loads given network list. 48 * @param {Array} networks An array of network object. 49 */ 50 load: function(networks) { 51 this.textContent = ''; 52 53 for (var i = 0; i < networks.length; ++i) { 54 this.appendChild(new NetworkItem(networks[i])); 55 } 56 }, 57 58 /** 59 * Handles click on network list and triggers actions when clicked on 60 * a NetworkListItem button. 61 * @private 62 * @param {!Event} e The click event object. 63 */ 64 handleClick_: function(e) { 65 // We shouldn't respond to click events selecting an input, 66 // so return on those. 67 if (e.target.tagName == 'INPUT') { 68 return; 69 } 70 // Handle left button click 71 if (e.button == 0) { 72 var el = e.target; 73 // If click is on action buttons of a network item. 74 if (!(el.buttonType && el.networkType && el.servicePath)) { 75 if (el.buttonType) { 76 return; 77 } 78 // If click is on a network item or its label, walk up the DOM tree 79 // to find the network item. 80 var item = el; 81 while (item && !item.data) { 82 item = item.parentNode; 83 } 84 if (item.connecting) 85 return; 86 87 if (item) { 88 var data = item.data; 89 // Don't try to connect to Ethernet or unactivated Cellular. 90 if (data && (data.networkType == 1 || 91 (data.networkType == 5 && data.activation_state != 1))) 92 return; 93 for (var i = 0; i < this.childNodes.length; i++) { 94 if (this.childNodes[i] != item) 95 this.childNodes[i].hidePassword(); 96 } 97 InternetOptions.unlockUpdates(); 98 // If clicked on other networks item. 99 if (data && data.servicePath == '?') { 100 if (InternetOptions.useSettingsUI && 101 data.type != options.internet.Constants.TYPE_CELLULAR) { 102 item.showOtherLogin(); 103 } else { 104 chrome.send('buttonClickCallback', 105 [String(data.networkType), 106 data.servicePath, 107 'connect']); 108 } 109 } 110 } 111 } 112 } 113 } 114 }; 115 116 /** 117 * Creates a new network item. 118 * @param {Object} network The network this represents. 119 * @constructor 120 * @extends {HTMLDivElement} 121 */ 122 function NetworkItem(network) { 123 var el = cr.doc.createElement('div'); 124 el.data = { 125 servicePath: network[0], 126 networkName: network[1], 127 networkStatus: network[2], 128 networkType: network[3], 129 connected: network[4], 130 connecting: network[5], 131 iconURL: network[6], 132 remembered: network[7], 133 activation_state: network[8], 134 needs_new_plan: network[9], 135 connectable: network[10] 136 }; 137 NetworkItem.decorate(el); 138 return el; 139 } 140 141 142 /** 143 * Decorates an element as a network item. 144 * @param {!HTMLElement} el The element to decorate. 145 */ 146 NetworkItem.decorate = function(el) { 147 el.__proto__ = NetworkItem.prototype; 148 el.decorate(); 149 }; 150 151 NetworkItem.prototype = { 152 __proto__: HTMLDivElement.prototype, 153 154 /** @inheritDoc */ 155 decorate: function() { 156 this.className = 'network-item'; 157 this.connected = this.data.connected; 158 this.connectable = this.data.connectable; 159 this.other = this.data.servicePath == '?'; 160 this.id = this.data.servicePath; 161 // textDiv holds icon, name and status text. 162 var textDiv = this.ownerDocument.createElement('div'); 163 textDiv.className = 'network-item-text'; 164 if (this.data.iconURL) { 165 textDiv.style.backgroundImage = url(this.data.iconURL); 166 } 167 168 var nameEl = this.ownerDocument.createElement('div'); 169 nameEl.className = 'network-name-label'; 170 nameEl.textContent = this.data.networkName; 171 textDiv.appendChild(nameEl); 172 173 if (this.other) { 174 // No status and buttons for "Other..." 175 this.appendChild(textDiv); 176 return; 177 } 178 179 // Only show status text for networks other than "remembered". 180 if (!this.data.remembered) { 181 var statusEl = this.ownerDocument.createElement('div'); 182 statusEl.className = 'network-status-label'; 183 statusEl.textContent = this.data.networkStatus; 184 textDiv.appendChild(statusEl); 185 } 186 187 this.appendChild(textDiv); 188 189 var spacerDiv = this.ownerDocument.createElement('div'); 190 spacerDiv.className = 'network-item-box-spacer'; 191 this.appendChild(spacerDiv); 192 193 var buttonsDiv = this.ownerDocument.createElement('div'); 194 var self = this; 195 if (!this.data.remembered) { 196 var no_plan = 197 this.data.networkType == Constants.TYPE_CELLULAR && 198 this.data.needs_new_plan; 199 var show_activate = 200 (this.data.networkType == Constants.TYPE_CELLULAR && 201 this.data.activation_state != 202 Constants.ACTIVATION_STATE_ACTIVATED && 203 this.data.activation_state != 204 Constants.ACTIVATION_STATE_ACTIVATING); 205 206 // Show [Activate] button for non-activated Cellular network. 207 if (show_activate || no_plan) { 208 var button_name = no_plan ? 'buyplan_button' : 'activate_button'; 209 buttonsDiv.appendChild( 210 this.createButton_(button_name, 'activate', 211 function(e) { 212 chrome.send('buttonClickCallback', 213 [String(self.data.networkType), 214 self.data.servicePath, 215 'activate']); 216 })); 217 } 218 // Show disconnect button if not ethernet. 219 if (this.data.networkType != Constants.TYPE_ETHERNET && 220 this.data.connected) { 221 buttonsDiv.appendChild( 222 this.createButton_('disconnect_button', 'disconnect', 223 function(e) { 224 chrome.send('buttonClickCallback', 225 [String(self.data.networkType), 226 self.data.servicePath, 227 'disconnect']); 228 })); 229 } 230 if (!this.data.connected && !this.data.connecting) { 231 // connect button (if not ethernet and not showing activate button) 232 if (this.data.networkType != Constants.TYPE_ETHERNET && 233 !show_activate && !no_plan) { 234 buttonsDiv.appendChild( 235 this.createButton_('connect_button', 'connect', 236 function(e) { 237 chrome.send('buttonClickCallback', 238 [String(self.data.networkType), 239 self.data.servicePath, 240 'connect']); 241 })); 242 } 243 } 244 if (this.data.connected || 245 this.data.networkType == Constants.TYPE_CELLULAR) { 246 buttonsDiv.appendChild( 247 this.createButton_('options_button', 'options', 248 function(e) { 249 chrome.send('buttonClickCallback', 250 [String(self.data.networkType), 251 self.data.servicePath, 252 'options']); 253 })); 254 } 255 } else { 256 // Put "Forget this network" button. 257 var button = this.createButton_('forget_button', 'forget', 258 function(e) { 259 chrome.send('buttonClickCallback', 260 [String(self.data.networkType), 261 self.data.servicePath, 262 'forget']); 263 }); 264 if (!AccountsOptions.currentUserIsOwner()) { 265 // Disable this for guest non-Owners. 266 button.disabled = true; 267 } 268 269 buttonsDiv.appendChild(button); 270 } 271 this.appendChild(buttonsDiv); 272 }, 273 274 showPassword: function() { 275 if (this.connecting) 276 return; 277 278 InternetOptions.lockUpdates(); 279 280 var passwordDiv = this.ownerDocument.createElement('div'); 281 passwordDiv.className = 'network-password'; 282 var passInput = this.ownerDocument.createElement('input'); 283 passwordDiv.appendChild(passInput); 284 passInput.placeholder = localStrings.getString('inetPassPrompt'); 285 passInput.type = 'password'; 286 var buttonEl = this.ownerDocument.createElement('button'); 287 buttonEl.textContent = localStrings.getString('inetLogin'); 288 buttonEl.addEventListener('click', this.handleLogin_); 289 buttonEl.servicePath = this.data.servicePath; 290 buttonEl.style.right = '0'; 291 buttonEl.style.position = 'absolute'; 292 buttonEl.style.visibility = 'visible'; 293 buttonEl.disabled = true; 294 295 var togglePassLabel = this.ownerDocument.createElement('label'); 296 togglePassLabel.style.display = 'inline'; 297 var togglePassSpan = this.ownerDocument.createElement('span'); 298 var togglePassCheckbox = this.ownerDocument.createElement('input'); 299 togglePassCheckbox.type = 'checkbox'; 300 togglePassCheckbox.checked = false; 301 togglePassCheckbox.target = passInput; 302 togglePassCheckbox.addEventListener('change', this.handleShowPass_); 303 togglePassSpan.textContent = localStrings.getString('inetShowPass'); 304 togglePassLabel.appendChild(togglePassCheckbox); 305 togglePassLabel.appendChild(togglePassSpan); 306 passwordDiv.appendChild(togglePassLabel); 307 308 // Disable login button if there is no password. 309 passInput.addEventListener('keyup', function(e) { 310 buttonEl.disabled = 311 passInput.value.length < Constants.MIN_WIRELESS_PASSWORD_LENGTH; 312 }); 313 314 passwordDiv.appendChild(buttonEl); 315 this.connecting = true; 316 this.appendChild(passwordDiv); 317 }, 318 319 handleShowPass_: function(e) { 320 var target = e.target; 321 if (target.checked) { 322 target.target.type = 'text'; 323 } else { 324 target.target.type = 'password'; 325 } 326 }, 327 328 hidePassword: function() { 329 this.connecting = false; 330 var children = this.childNodes; 331 // Remove all password divs starting from the end. 332 for (var i = children.length-1; i >= 0; i--) { 333 if (children[i].className == 'network-password') { 334 this.removeChild(children[i]); 335 } 336 } 337 }, 338 339 showOtherLogin: function() { 340 if (this.connecting) 341 return; 342 343 InternetOptions.lockUpdates(); 344 345 var ssidDiv = this.ownerDocument.createElement('div'); 346 ssidDiv.className = 'network-password'; 347 var ssidInput = this.ownerDocument.createElement('input'); 348 ssidInput.placeholder = localStrings.getString('inetSsidPrompt'); 349 ssidDiv.appendChild(ssidInput); 350 351 var securityDiv = this.ownerDocument.createElement('div'); 352 securityDiv.className = 'network-password'; 353 var securityInput = this.ownerDocument.createElement('select'); 354 var securityNoneOption = this.ownerDocument.createElement('option'); 355 securityNoneOption.value = 'none'; 356 securityNoneOption.label = localStrings.getString('inetSecurityNone'); 357 securityInput.appendChild(securityNoneOption); 358 var securityWEPOption = this.ownerDocument.createElement('option'); 359 securityWEPOption.value = 'wep'; 360 securityWEPOption.label = localStrings.getString('inetSecurityWEP'); 361 securityInput.appendChild(securityWEPOption); 362 var securityWPAOption = this.ownerDocument.createElement('option'); 363 securityWPAOption.value = 'wpa'; 364 securityWPAOption.label = localStrings.getString('inetSecurityWPA'); 365 securityInput.appendChild(securityWPAOption); 366 var securityRSNOption = this.ownerDocument.createElement('option'); 367 securityRSNOption.value = 'rsn'; 368 securityRSNOption.label = localStrings.getString('inetSecurityRSN'); 369 securityInput.appendChild(securityRSNOption); 370 securityDiv.appendChild(securityInput); 371 372 var passwordDiv = this.ownerDocument.createElement('div'); 373 passwordDiv.className = 'network-password'; 374 var passInput = this.ownerDocument.createElement('input'); 375 passInput.placeholder = localStrings.getString('inetPassPrompt'); 376 passInput.type = 'password'; 377 passInput.disabled = true; 378 passwordDiv.appendChild(passInput); 379 380 var togglePassLabel = this.ownerDocument.createElement('label'); 381 togglePassLabel.style.display = 'inline'; 382 var togglePassSpan = this.ownerDocument.createElement('span'); 383 var togglePassCheckbox = this.ownerDocument.createElement('input'); 384 togglePassCheckbox.type = 'checkbox'; 385 togglePassCheckbox.checked = false; 386 togglePassCheckbox.target = passInput; 387 togglePassCheckbox.addEventListener('change', this.handleShowPass_); 388 togglePassSpan.textContent = localStrings.getString('inetShowPass'); 389 togglePassLabel.appendChild(togglePassCheckbox); 390 togglePassLabel.appendChild(togglePassSpan); 391 passwordDiv.appendChild(togglePassLabel); 392 393 var buttonEl = 394 this.createButton_('inetLogin', true, this.handleOtherLogin_); 395 buttonEl.style.right = '0'; 396 buttonEl.style.position = 'absolute'; 397 buttonEl.style.visibility = 'visible'; 398 buttonEl.disabled = true; 399 passwordDiv.appendChild(buttonEl); 400 401 this.appendChild(ssidDiv); 402 this.appendChild(securityDiv); 403 this.appendChild(passwordDiv); 404 405 securityInput.addEventListener('change', function(e) { 406 // If changed to None, then disable passInput and clear it out. 407 // Otherwise enable it. 408 if (securityInput.value == 'none') { 409 passInput.disabled = true; 410 passInput.value = ''; 411 } else { 412 passInput.disabled = false; 413 } 414 }); 415 416 var keyup_listener = function(e) { 417 // Disable login button if ssid is not long enough or 418 // password is not long enough (unless no security) 419 var ssid_good = 420 ssidInput.value.length >= Constants.MIN_WIRELESS_SSID_LENGTH; 421 var pass_good = 422 securityInput.value == 'none' || 423 passInput.value.length >= Constants.MIN_WIRELESS_PASSWORD_LENGTH; 424 buttonEl.disabled = !ssid_good || !pass_good; 425 }; 426 ssidInput.addEventListener('keyup', keyup_listener); 427 securityInput.addEventListener('change', keyup_listener); 428 passInput.addEventListener('keyup', keyup_listener); 429 this.connecting = true; 430 }, 431 432 handleLogin_: function(e) { 433 // The user has clicked on the Login button. It's now safe to 434 // unclock UI updates. 435 InternetOptions.unlockUpdates(); 436 var el = e.target; 437 var parent = el.parentNode; 438 el.disabled = true; 439 var input = parent.firstChild; 440 input.disabled = true; 441 chrome.send('loginToNetwork', [el.servicePath, input.value]); 442 }, 443 444 handleOtherLogin_: function(e) { 445 // See comments in handleLogin_(). 446 InternetOptions.unlockUpdates(); 447 var el = e.target; 448 var parent = el.parentNode.parentNode; 449 el.disabled = true; 450 var ssid = parent.childNodes[1].firstChild; 451 var sec = parent.childNodes[2].firstChild; 452 var pass = parent.childNodes[3].firstChild; 453 sec.disabled = true; 454 ssid.disabled = true; 455 pass.disabled = true; 456 chrome.send('loginToOtherNetwork', [sec.value, ssid.value, pass.value]); 457 }, 458 459 /** 460 * Creates a button for interacting with a network. 461 * @param {Object} name The name of the localStrings to use for the text. 462 * @param {Object} type The type of button. 463 */ 464 createButton_: function(name, type, callback) { 465 var buttonEl = this.ownerDocument.createElement('button'); 466 buttonEl.buttonType = type; 467 buttonEl.textContent = localStrings.getString(name); 468 buttonEl.addEventListener('click', callback); 469 return buttonEl; 470 } 471 }; 472 473 /** 474 * Whether the underlying network is connected. Only used for display purpose. 475 * @type {boolean} 476 */ 477 cr.defineProperty(NetworkItem, 'connected', cr.PropertyKind.BOOL_ATTR); 478 479 /** 480 * Whether the underlying network is currently connecting. 481 * Only used for display purpose. 482 * @type {boolean} 483 */ 484 cr.defineProperty(NetworkItem, 'connecting', cr.PropertyKind.BOOL_ATTR); 485 486 /** 487 * Whether the underlying network is an other network for adding networks. 488 * Only used for display purpose. 489 * @type {boolean} 490 */ 491 cr.defineProperty(NetworkItem, 'other', cr.PropertyKind.BOOL_ATTR); 492 493 /** 494 * Whether the underlying network is connectable. 495 * @type {boolean} 496 */ 497 cr.defineProperty(NetworkItem, 'connectable', cr.PropertyKind.BOOL_ATTR); 498 499 return { 500 Constants: Constants, 501 NetworkElement: NetworkElement 502 }; 503 }); 504