1 // Copyright (c) 2012 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 <include src="../uber/uber_utils.js"> 6 7 cr.define('help', function() { 8 /** 9 * Encapsulated handling of the help page. 10 */ 11 function HelpPage() {} 12 13 cr.addSingletonGetter(HelpPage); 14 15 HelpPage.prototype = { 16 __proto__: help.HelpBasePage.prototype, 17 18 /** 19 * True if after update powerwash button should be displayed. 20 * @private 21 */ 22 powerwashAfterUpdate_: false, 23 24 /** 25 * List of the channels names. 26 * @private 27 */ 28 channelList_: ['dev-channel', 'beta-channel', 'stable-channel'], 29 30 /** 31 * Bubble for error messages and notifications. 32 * @private 33 */ 34 bubble_: null, 35 36 /** 37 * Name of the channel the device is currently on. 38 * @private 39 */ 40 currentChannel_: null, 41 42 /** 43 * Name of the channel the device is supposed to be on. 44 * @private 45 */ 46 targetChannel_: null, 47 48 /** 49 * Perform initial setup. 50 */ 51 initialize: function() { 52 help.HelpBasePage.prototype.initialize.call(this, 'help-page'); 53 54 var self = this; 55 56 uber.onContentFrameLoaded(); 57 58 // Set the title. 59 var title = loadTimeData.getString('helpTitle'); 60 uber.invokeMethodOnParent('setTitle', {title: title}); 61 62 $('product-license').innerHTML = loadTimeData.getString('productLicense'); 63 if (cr.isChromeOS) { 64 $('product-os-license').innerHTML = 65 loadTimeData.getString('productOsLicense'); 66 } 67 68 var productTOS = $('product-tos'); 69 if (productTOS) 70 productTOS.innerHTML = loadTimeData.getString('productTOS'); 71 72 $('get-help').onclick = function() { 73 chrome.send('openHelpPage'); 74 }; 75 <if expr="pp_ifdef('_google_chrome')"> 76 $('report-issue').onclick = function() { 77 chrome.send('openFeedbackDialog'); 78 }; 79 </if> 80 81 this.maybeSetOnClick_($('more-info-expander'), 82 this.toggleMoreInfo_.bind(this)); 83 84 this.maybeSetOnClick_($('promote'), function() { 85 chrome.send('promoteUpdater'); 86 }); 87 this.maybeSetOnClick_($('relaunch'), function() { 88 chrome.send('relaunchNow'); 89 }); 90 if (cr.isChromeOS) { 91 this.maybeSetOnClick_($('relaunch-and-powerwash'), function() { 92 chrome.send('relaunchAndPowerwash'); 93 }); 94 95 this.channelTable_ = { 96 'stable-channel': { 97 'name': loadTimeData.getString('stable'), 98 'label': loadTimeData.getString('currentChannelStable'), 99 }, 100 'beta-channel': { 101 'name': loadTimeData.getString('beta'), 102 'label': loadTimeData.getString('currentChannelBeta') 103 }, 104 'dev-channel': { 105 'name': loadTimeData.getString('dev'), 106 'label': loadTimeData.getString('currentChannelDev') 107 } 108 }; 109 } 110 111 var channelChanger = $('channel-changer'); 112 if (channelChanger) { 113 channelChanger.onchange = function(event) { 114 self.setChannel_(event.target.value, false); 115 }; 116 } 117 118 if (cr.isChromeOS) { 119 help.ChannelChangePage.getInstance().initialize(); 120 this.registerOverlay(help.ChannelChangePage.getInstance()); 121 122 cr.ui.overlay.setupOverlay($('overlay-container')); 123 cr.ui.overlay.globalInitialization(); 124 $('overlay-container').addEventListener('cancelOverlay', function() { 125 self.closeOverlay(); 126 }); 127 $('change-channel').onclick = function() { 128 self.showOverlay('channel-change-page'); 129 }; 130 131 var channelChangeDisallowedError = document.createElement('div'); 132 channelChangeDisallowedError.className = 'channel-change-error-bubble'; 133 134 var channelChangeDisallowedIcon = document.createElement('div'); 135 channelChangeDisallowedIcon.classList.add('help-page-icon-large'); 136 channelChangeDisallowedIcon.classList.add('channel-change-error-icon'); 137 channelChangeDisallowedError.appendChild(channelChangeDisallowedIcon); 138 139 var channelChangeDisallowedText = document.createElement('div'); 140 channelChangeDisallowedText.className = 'channel-change-error-text'; 141 channelChangeDisallowedText.textContent = 142 loadTimeData.getString('channelChangeDisallowedMessage'); 143 channelChangeDisallowedError.appendChild(channelChangeDisallowedText); 144 145 $('channel-change-disallowed-icon').onclick = function() { 146 self.showBubble_(channelChangeDisallowedError, 147 $('help-container'), 148 $('channel-change-disallowed-icon'), 149 cr.ui.ArrowLocation.TOP_END); 150 }; 151 } 152 153 cr.ui.FocusManager.disableMouseFocusOnButtons(); 154 help.HelpFocusManager.getInstance().initialize(); 155 156 // Attempt to update. 157 chrome.send('onPageLoaded'); 158 }, 159 160 /** 161 * Shows the bubble. 162 * @param {HTMLDivElement} content The content of the bubble. 163 * @param {HTMLElement} target The element at which the bubble points. 164 * @param {HTMLElement} domSibling The element after which the bubble is 165 * added to the DOM. 166 * @param {cr.ui.ArrowLocation} location The arrow location. 167 * @private 168 */ 169 showBubble_: function(content, domSibling, target, location) { 170 if (!cr.isChromeOS) 171 return; 172 this.hideBubble_(); 173 var bubble = new cr.ui.AutoCloseBubble; 174 bubble.anchorNode = target; 175 bubble.domSibling = domSibling; 176 bubble.arrowLocation = location; 177 bubble.content = content; 178 bubble.show(); 179 this.bubble_ = bubble; 180 }, 181 182 /** 183 * Hides the bubble. 184 * @private 185 */ 186 hideBubble_: function() { 187 if (!cr.isChromeOS) 188 return; 189 if (this.bubble_) 190 this.bubble_.hide(); 191 }, 192 193 /** 194 * Toggles the visible state of the 'More Info' section. 195 * @private 196 */ 197 toggleMoreInfo_: function() { 198 var moreInfo = $('more-info-container'); 199 var visible = moreInfo.className == 'visible'; 200 moreInfo.className = visible ? '' : 'visible'; 201 moreInfo.style.height = visible ? '' : moreInfo.scrollHeight + 'px'; 202 moreInfo.addEventListener('webkitTransitionEnd', function(event) { 203 $('more-info-expander').textContent = visible ? 204 loadTimeData.getString('showMoreInfo') : 205 loadTimeData.getString('hideMoreInfo'); 206 }); 207 }, 208 209 /** 210 * Assigns |method| to the onclick property of |el| if |el| exists. 211 * @private 212 */ 213 maybeSetOnClick_: function(el, method) { 214 if (el) 215 el.onclick = method; 216 }, 217 218 /** 219 * @private 220 */ 221 setUpdateImage_: function(state) { 222 $('update-status-icon').className = 'help-page-icon ' + state; 223 }, 224 225 /** 226 * @return {boolean} True, if new channel switcher UI is used, 227 * false otherwise. 228 * @private 229 */ 230 isNewChannelSwitcherUI_: function() { 231 return !loadTimeData.valueExists('disableNewChannelSwitcherUI'); 232 }, 233 234 /** 235 * @return {boolean} True if target and current channels are not 236 * null and not equals 237 * @private 238 */ 239 channelsDiffer_: function() { 240 var current = this.currentChannel_; 241 var target = this.targetChannel_; 242 return (current != null && target != null && current != target); 243 }, 244 245 /** 246 * @private 247 */ 248 setUpdateStatus_: function(status, message) { 249 var channel = this.targetChannel_; 250 if (status == 'checking') { 251 this.setUpdateImage_('working'); 252 $('update-status-message').innerHTML = 253 loadTimeData.getString('updateCheckStarted'); 254 } else if (status == 'updating') { 255 this.setUpdateImage_('working'); 256 if (this.channelsDiffer_()) { 257 $('update-status-message').innerHTML = 258 loadTimeData.getStringF('updatingChannelSwitch', 259 this.channelTable_[channel].label); 260 } else { 261 $('update-status-message').innerHTML = 262 loadTimeData.getStringF('updating'); 263 } 264 } else if (status == 'nearly_updated') { 265 this.setUpdateImage_('up-to-date'); 266 if (this.channelsDiffer_()) { 267 $('update-status-message').innerHTML = 268 loadTimeData.getString('successfulChannelSwitch'); 269 } else { 270 $('update-status-message').innerHTML = 271 loadTimeData.getString('updateAlmostDone'); 272 } 273 } else if (status == 'updated') { 274 this.setUpdateImage_('up-to-date'); 275 $('update-status-message').innerHTML = 276 loadTimeData.getString('upToDate'); 277 } else if (status == 'failed') { 278 this.setUpdateImage_('failed'); 279 $('update-status-message').innerHTML = message; 280 } 281 282 // Following invariant must be established at the end of this function: 283 // { ~$('relaunch_and_powerwash').hidden -> $('relaunch').hidden } 284 var relaunchAndPowerwashHidden = true; 285 if ($('relaunch-and-powerwash')) { 286 // It's allowed to do powerwash only for customer devices, 287 // when user explicitly decides to update to a more stable 288 // channel. 289 relaunchAndPowerwashHidden = 290 !this.powerwashAfterUpdate_ || status != 'nearly_updated'; 291 $('relaunch-and-powerwash').hidden = relaunchAndPowerwashHidden; 292 } 293 294 var container = $('update-status-container'); 295 if (container) { 296 container.hidden = status == 'disabled'; 297 $('relaunch').hidden = 298 (status != 'nearly_updated') || !relaunchAndPowerwashHidden; 299 300 if (!cr.isMac) 301 $('update-percentage').hidden = status != 'updating'; 302 } 303 }, 304 305 /** 306 * @private 307 */ 308 setProgress_: function(progress) { 309 $('update-percentage').innerHTML = progress + '%'; 310 }, 311 312 /** 313 * @private 314 */ 315 setAllowedConnectionTypesMsg_: function(message) { 316 $('allowed-connection-types-message').innerText = message; 317 }, 318 319 /** 320 * @private 321 */ 322 showAllowedConnectionTypesMsg_: function(visible) { 323 $('allowed-connection-types-message').hidden = !visible; 324 }, 325 326 /** 327 * @private 328 */ 329 setPromotionState_: function(state) { 330 if (state == 'hidden') { 331 $('promote').hidden = true; 332 } else if (state == 'enabled') { 333 $('promote').disabled = false; 334 $('promote').hidden = false; 335 } else if (state == 'disabled') { 336 $('promote').disabled = true; 337 $('promote').hidden = false; 338 } 339 }, 340 341 /** 342 * @private 343 */ 344 setOSVersion_: function(version) { 345 if (!cr.isChromeOS) 346 console.error('OS version unsupported on non-CrOS'); 347 348 $('os-version').parentNode.hidden = (version == ''); 349 $('os-version').textContent = version; 350 }, 351 352 /** 353 * @private 354 */ 355 setOSFirmware_: function(firmware) { 356 if (!cr.isChromeOS) 357 console.error('OS firmware unsupported on non-CrOS'); 358 359 $('firmware').parentNode.hidden = (firmware == ''); 360 $('firmware').textContent = firmware; 361 }, 362 363 /** 364 * Updates name of the current channel, i.e. the name of the 365 * channel the device is currently on. 366 * @param {string} channel The name of the current channel 367 * @private 368 */ 369 updateCurrentChannel_: function(channel) { 370 if (this.channelList_.indexOf(channel) < 0) 371 return; 372 $('current-channel').textContent = loadTimeData.getStringF( 373 'currentChannel', this.channelTable_[channel].label); 374 this.currentChannel_ = channel; 375 help.ChannelChangePage.updateCurrentChannel(channel); 376 }, 377 378 /** 379 * |enabled| is true if the release channel can be enabled. 380 * @private 381 */ 382 updateEnableReleaseChannel_: function(enabled) { 383 this.updateChannelChangerContainerVisibility_(enabled); 384 $('change-channel').disabled = !enabled; 385 $('channel-change-disallowed-icon').hidden = enabled; 386 }, 387 388 /** 389 * Sets the device target channel. 390 * @param {string} channel The name of the target channel 391 * @param {boolean} isPowerwashAllowed True iff powerwash is allowed 392 * @private 393 */ 394 setChannel_: function(channel, isPowerwashAllowed) { 395 this.powerwashAfterUpdate_ = isPowerwashAllowed; 396 this.targetChannel_ = channel; 397 chrome.send('setChannel', [channel, isPowerwashAllowed]); 398 $('channel-change-confirmation').hidden = false; 399 $('channel-change-confirmation').textContent = loadTimeData.getStringF( 400 'channel-changed', this.channelTable_[channel].name); 401 }, 402 403 /** 404 * Sets the value of the "Build Date" field of the "More Info" section. 405 * @param {string} buildDate The date of the build. 406 * @private 407 */ 408 setBuildDate_: function(buildDate) { 409 $('build-date-container').classList.remove('empty'); 410 $('build-date').textContent = buildDate; 411 }, 412 413 /** 414 * Updates channel-change-page-container visibility according to 415 * internal state. 416 * @private 417 */ 418 updateChannelChangePageContainerVisibility_: function() { 419 if (!this.isNewChannelSwitcherUI_()) { 420 $('channel-change-page-container').hidden = true; 421 return; 422 } 423 $('channel-change-page-container').hidden = 424 !help.ChannelChangePage.isPageReady(); 425 }, 426 427 /** 428 * Updates channel-changer dropdown visibility if |visible| is 429 * true and new channel switcher UI is disallowed. 430 * @param {boolean} visible True if channel-changer should be 431 * displayed, false otherwise. 432 * @private 433 */ 434 updateChannelChangerContainerVisibility_: function(visible) { 435 if (this.isNewChannelSwitcherUI_()) { 436 $('channel-changer').hidden = true; 437 return; 438 } 439 $('channel-changer').hidden = !visible; 440 }, 441 }; 442 443 HelpPage.setUpdateStatus = function(status, message) { 444 HelpPage.getInstance().setUpdateStatus_(status, message); 445 }; 446 447 HelpPage.setProgress = function(progress) { 448 HelpPage.getInstance().setProgress_(progress); 449 }; 450 451 HelpPage.setAndShowAllowedConnectionTypesMsg = function(message) { 452 HelpPage.getInstance().setAllowedConnectionTypesMsg_(message); 453 HelpPage.getInstance().showAllowedConnectionTypesMsg_(true); 454 }; 455 456 HelpPage.showAllowedConnectionTypesMsg = function(visible) { 457 HelpPage.getInstance().showAllowedConnectionTypesMsg_(visible); 458 }; 459 460 HelpPage.setPromotionState = function(state) { 461 HelpPage.getInstance().setPromotionState_(state); 462 }; 463 464 HelpPage.setObsoleteOS = function(obsolete) { 465 HelpPage.getInstance().setObsoleteOS_(obsolete); 466 }; 467 468 HelpPage.setOSVersion = function(version) { 469 HelpPage.getInstance().setOSVersion_(version); 470 }; 471 472 HelpPage.setOSFirmware = function(firmware) { 473 HelpPage.getInstance().setOSFirmware_(firmware); 474 }; 475 476 HelpPage.showOverlay = function(name) { 477 HelpPage.getInstance().showOverlay(name); 478 }; 479 480 HelpPage.cancelOverlay = function() { 481 HelpPage.getInstance().closeOverlay(); 482 }; 483 484 HelpPage.getTopmostVisiblePage = function() { 485 return HelpPage.getInstance().getTopmostVisiblePage(); 486 }; 487 488 HelpPage.updateIsEnterpriseManaged = function(isEnterpriseManaged) { 489 if (!cr.isChromeOS) 490 return; 491 help.ChannelChangePage.updateIsEnterpriseManaged(isEnterpriseManaged); 492 }; 493 494 HelpPage.updateCurrentChannel = function(channel) { 495 if (!cr.isChromeOS) 496 return; 497 HelpPage.getInstance().updateCurrentChannel_(channel); 498 }; 499 500 HelpPage.updateTargetChannel = function(channel) { 501 if (!cr.isChromeOS) 502 return; 503 help.ChannelChangePage.updateTargetChannel(channel); 504 }; 505 506 HelpPage.updateEnableReleaseChannel = function(enabled) { 507 HelpPage.getInstance().updateEnableReleaseChannel_(enabled); 508 }; 509 510 HelpPage.setChannel = function(channel, isPowerwashAllowed) { 511 HelpPage.getInstance().setChannel_(channel, isPowerwashAllowed); 512 }; 513 514 HelpPage.setBuildDate = function(buildDate) { 515 HelpPage.getInstance().setBuildDate_(buildDate); 516 }; 517 518 HelpPage.updateChannelChangePageContainerVisibility = function() { 519 HelpPage.getInstance().updateChannelChangePageContainerVisibility_(); 520 }; 521 522 // Export 523 return { 524 HelpPage: HelpPage 525 }; 526 }); 527 528 /** 529 * onload listener to initialize the HelpPage. 530 */ 531 window.onload = function() { 532 help.HelpPage.getInstance().initialize(); 533 }; 534