1 // Copyright 2014 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.
5 cr.define('help', function() {
6 var Page = cr.ui.pageManager.Page;
7 var PageManager = cr.ui.pageManager.PageManager;
10 * Encapsulated handling of the About page. Called 'help' internally to avoid
11 * confusion with generic AboutUI (about:memory, about:sandbox, etc.).
14 var id = loadTimeData.valueExists('aboutOverlayTabTitle') ?
15 'aboutOverlayTabTitle' : 'aboutTitle';
16 Page.call(this, 'help', loadTimeData.getString(id), 'help-page');
19 cr.addSingletonGetter(HelpPage);
21 HelpPage.prototype = {
22 __proto__: Page.prototype,
25 * List of the channel names. Should be ordered in increasing level of
29 channelList_: ['dev-channel', 'beta-channel', 'stable-channel'],
32 * Name of the channel the device is currently on.
35 currentChannel_: null,
38 * Name of the channel the device is supposed to be on.
44 * Last status received from the version updater.
50 * Last message received from the version updater.
56 * True if user is allowed to change channels, false otherwise.
59 can_change_channel_: false,
62 initializePage: function() {
63 Page.prototype.initializePage.call(this);
65 $('product-license').innerHTML = loadTimeData.getString('productLicense');
67 $('product-os-license').innerHTML =
68 loadTimeData.getString('productOsLicense');
71 var productTOS = $('product-tos');
73 productTOS.innerHTML = loadTimeData.getString('productTOS');
75 $('get-help').onclick = function() {
76 chrome.send('openHelpPage');
78 <if expr="_google_chrome">
79 $('report-issue').onclick = function() {
80 chrome.send('openFeedbackDialog');
84 this.maybeSetOnClick_($('more-info-expander'),
85 this.toggleMoreInfo_.bind(this));
87 this.maybeSetOnClick_($('promote'), function() {
88 chrome.send('promoteUpdater');
90 this.maybeSetOnClick_($('relaunch'), function() {
91 chrome.send('relaunchNow');
94 this.maybeSetOnClick_($('relaunch-and-powerwash'), function() {
95 chrome.send('relaunchAndPowerwash');
98 this.channelTable_ = {
100 'name': loadTimeData.getString('stable'),
101 'label': loadTimeData.getString('currentChannelStable'),
104 'name': loadTimeData.getString('beta'),
105 'label': loadTimeData.getString('currentChannelBeta')
108 'name': loadTimeData.getString('dev'),
109 'label': loadTimeData.getString('currentChannelDev')
113 this.maybeSetOnClick_($('about-done'), function() {
114 // Event listener for the close button when shown as an overlay.
115 PageManager.closeOverlay();
119 var channelChanger = $('channel-changer');
120 if (channelChanger) {
121 channelChanger.onchange = function(event) {
122 self.setChannel_(event.target.value, false);
127 // Add event listener for the check for and apply updates button.
128 this.maybeSetOnClick_($('request-update'), function() {
129 self.setUpdateStatus_('checking');
130 $('request-update').disabled = true;
131 chrome.send('requestUpdate');
134 $('change-channel').onclick = function() {
135 PageManager.showPageByName('channel-change-page', false);
138 var channelChangeDisallowedError = document.createElement('div');
139 channelChangeDisallowedError.className = 'channel-change-error-bubble';
141 var channelChangeDisallowedIcon = document.createElement('div');
142 channelChangeDisallowedIcon.classList.add('help-page-icon-large');
143 channelChangeDisallowedIcon.classList.add('channel-change-error-icon');
144 channelChangeDisallowedError.appendChild(channelChangeDisallowedIcon);
146 var channelChangeDisallowedText = document.createElement('div');
147 channelChangeDisallowedText.className = 'channel-change-error-text';
148 channelChangeDisallowedText.textContent =
149 loadTimeData.getString('channelChangeDisallowedMessage');
150 channelChangeDisallowedError.appendChild(channelChangeDisallowedText);
152 $('channel-change-disallowed-icon').onclick = function() {
153 PageManager.showBubble(channelChangeDisallowedError,
154 $('channel-change-disallowed-icon'),
156 cr.ui.ArrowLocation.TOP_END);
159 // Unhide the product label if/when the image loads.
160 var productLabel = $('product-label');
161 var show = function() { $('product-label-container').hidden = false; };
162 if (productLabel.naturalWidth)
165 productLabel.onload = show;
168 var logo = $('product-logo');
169 logo.onclick = function(e) {
170 logo.classList.remove('spin');
171 setTimeout(function() { logo.classList.add('spin'); }, 0);
174 // Attempt to update.
175 chrome.send('onPageLoaded');
179 didClosePage: function() {
180 this.setMoreInfoVisible_(false);
184 * Sets the visible state of the 'More Info' section.
185 * @param {boolean} visible Whether the section should be visible.
188 setMoreInfoVisible_: function(visible) {
189 var moreInfo = $('more-info-container');
190 if (!moreInfo || visible == moreInfo.classList.contains('visible'))
193 moreInfo.classList.toggle('visible', visible);
194 moreInfo.style.height = visible ? moreInfo.scrollHeight + 'px' : '';
195 moreInfo.addEventListener('webkitTransitionEnd', function(event) {
196 $('more-info-expander').textContent = visible ?
197 loadTimeData.getString('hideMoreInfo') :
198 loadTimeData.getString('showMoreInfo');
203 * Toggles the visible state of the 'More Info' section.
206 toggleMoreInfo_: function() {
207 var moreInfo = $('more-info-container');
208 this.setMoreInfoVisible_(!moreInfo.classList.contains('visible'));
212 * Assigns |method| to the onclick property of |el| if |el| exists.
213 * @param {HTMLElement} el The element on which to set the click handler.
214 * @param {Function} method The click handler.
217 maybeSetOnClick_: function(el, method) {
223 * @param {string} state The state of the update.
226 setUpdateImage_: function(state) {
227 $('update-status-icon').className = 'help-page-icon ' + state;
231 * @return {boolean} True, if new channel switcher UI is used,
235 isNewChannelSwitcherUI_: function() {
236 return !loadTimeData.valueExists('disableNewChannelSwitcherUI');
240 * @return {boolean} True if target and current channels are not null and
244 channelsDiffer_: function() {
245 var current = this.currentChannel_;
246 var target = this.targetChannel_;
247 return (current != null && target != null && current != target);
251 * @return {boolean} True if target channel is more stable than the current
252 * one, and false otherwise.
255 targetChannelIsMoreStable_: function() {
256 var current = this.currentChannel_;
257 var target = this.targetChannel_;
258 if (current == null || target == null)
260 var currentIndex = this.channelList_.indexOf(current);
261 var targetIndex = this.channelList_.indexOf(target);
262 if (currentIndex < 0 || targetIndex < 0)
264 return currentIndex < targetIndex;
268 * @param {string} status The status of the update.
269 * @param {string} message Failure message to display.
272 setUpdateStatus_: function(status, message) {
273 this.status_ = status;
274 this.message_ = message;
280 * Updates UI elements on the page according to current state.
283 updateUI_: function() {
284 var status = this.status_;
285 var message = this.message_;
286 var channel = this.targetChannel_;
288 if (this.channelList_.indexOf(channel) >= 0) {
289 $('current-channel').textContent = loadTimeData.getStringF(
290 'currentChannel', this.channelTable_[channel].label);
291 this.updateChannelChangePageContainerVisibility_();
298 $('update-status-message') &&
299 $('update-status-message').hidden) {
300 // Chrome has reached the end of the line on this system. The
301 // update-obsolete-system message is displayed. No other auto-update
302 // status should be displayed.
306 if (status == 'checking') {
307 this.setUpdateImage_('working');
308 $('update-status-message').innerHTML =
309 loadTimeData.getString('updateCheckStarted');
310 } else if (status == 'updating') {
311 this.setUpdateImage_('working');
312 if (this.channelsDiffer_()) {
313 $('update-status-message').innerHTML =
314 loadTimeData.getStringF('updatingChannelSwitch',
315 this.channelTable_[channel].label);
317 $('update-status-message').innerHTML =
318 loadTimeData.getStringF('updating');
320 } else if (status == 'nearly_updated') {
321 this.setUpdateImage_('up-to-date');
322 if (this.channelsDiffer_()) {
323 $('update-status-message').innerHTML =
324 loadTimeData.getString('successfulChannelSwitch');
326 $('update-status-message').innerHTML =
327 loadTimeData.getString('updateAlmostDone');
329 } else if (status == 'updated') {
330 this.setUpdateImage_('up-to-date');
331 $('update-status-message').innerHTML =
332 loadTimeData.getString('upToDate');
333 } else if (status == 'failed') {
334 this.setUpdateImage_('failed');
335 $('update-status-message').innerHTML = message;
339 $('change-channel').disabled = !this.can_change_channel_ ||
340 status == 'nearly_updated';
341 $('channel-change-disallowed-icon').hidden = this.can_change_channel_;
344 // Following invariant must be established at the end of this function:
345 // { ~$('relaunch_and_powerwash').hidden -> $('relaunch').hidden }
346 var relaunchAndPowerwashHidden = true;
347 if ($('relaunch-and-powerwash')) {
348 // It's allowed to do powerwash only for customer devices,
349 // when user explicitly decides to update to a more stable
351 relaunchAndPowerwashHidden =
352 !this.targetChannelIsMoreStable_() || status != 'nearly_updated';
353 $('relaunch-and-powerwash').hidden = relaunchAndPowerwashHidden;
357 // Only enable the update button if it hasn't been used yet or the
358 // status isn't 'updated'.
359 if (!$('request-update').disabled || status != 'updated') {
360 // Disable the button if an update is already in progress.
361 $('request-update').disabled =
362 ['checking', 'updating', 'nearly_updated'].indexOf(status) > -1;
366 var container = $('update-status-container');
368 container.hidden = status == 'disabled';
369 $('relaunch').hidden =
370 (status != 'nearly_updated') || !relaunchAndPowerwashHidden;
373 // Assume the "updated" status is stale if we haven't checked yet.
374 if (status == 'updated' && !$('request-update').disabled)
375 container.hidden = true;
377 // Hide the request update button if auto-updating is disabled or
378 // a relaunch button is showing.
379 $('request-update').hidden = status == 'disabled' ||
380 !$('relaunch').hidden || !relaunchAndPowerwashHidden;
384 $('update-percentage').hidden = status != 'updating';
389 * @param {number} progress The percent completion.
392 setProgress_: function(progress) {
393 $('update-percentage').innerHTML = progress + '%';
397 * @param {string} message The allowed connection types message.
400 setAllowedConnectionTypesMsg_: function(message) {
401 $('allowed-connection-types-message').innerText = message;
405 * @param {boolean} visible Whether to show the message.
408 showAllowedConnectionTypesMsg_: function(visible) {
409 $('allowed-connection-types-message').hidden = !visible;
413 * @param {string} state The promote state to set.
416 setPromotionState_: function(state) {
417 if (state == 'hidden') {
418 $('promote').hidden = true;
419 } else if (state == 'enabled') {
420 $('promote').disabled = false;
421 $('promote').hidden = false;
422 } else if (state == 'disabled') {
423 $('promote').disabled = true;
424 $('promote').hidden = false;
429 * @param {boolean} obsolete Whether the system is obsolete.
432 setObsoleteSystem_: function(obsolete) {
433 if (cr.isMac && $('update-obsolete-system-container')) {
434 $('update-obsolete-system-container').hidden = !obsolete;
439 * @param {boolean} endOfTheLine Whether the train has rolled into
443 setObsoleteSystemEndOfTheLine_: function(endOfTheLine) {
445 $('update-obsolete-system-container') &&
446 !$('update-obsolete-system-container').hidden &&
447 $('update-status-message')) {
448 $('update-status-message').hidden = endOfTheLine;
450 this.setUpdateImage_('failed');
456 * @param {string} version Version of Chrome OS.
459 setOSVersion_: function(version) {
461 console.error('OS version unsupported on non-CrOS');
463 $('os-version').parentNode.hidden = (version == '');
464 $('os-version').textContent = version;
468 * @param {string} firmware Firmware on Chrome OS.
471 setOSFirmware_: function(firmware) {
473 console.error('OS firmware unsupported on non-CrOS');
475 $('firmware').parentNode.hidden = (firmware == '');
476 $('firmware').textContent = firmware;
480 * Updates page UI according to device owhership policy.
481 * @param {boolean} isEnterpriseManaged True if the device is
482 * enterprise managed.
485 updateIsEnterpriseManaged_: function(isEnterpriseManaged) {
486 help.ChannelChangePage.updateIsEnterpriseManaged(isEnterpriseManaged);
491 * Updates name of the current channel, i.e. the name of the
492 * channel the device is currently on.
493 * @param {string} channel The name of the current channel.
496 updateCurrentChannel_: function(channel) {
497 if (this.channelList_.indexOf(channel) < 0)
499 this.currentChannel_ = channel;
500 help.ChannelChangePage.updateCurrentChannel(channel);
505 * Updates name of the target channel, i.e. the name of the
506 * channel the device is supposed to be.
507 * @param {string} channel The name of the target channel.
510 updateTargetChannel_: function(channel) {
511 if (this.channelList_.indexOf(channel) < 0)
513 this.targetChannel_ = channel;
514 help.ChannelChangePage.updateTargetChannel(channel);
519 * @param {boolean} enabled True if the release channel can be enabled.
522 updateEnableReleaseChannel_: function(enabled) {
523 this.updateChannelChangerContainerVisibility_(enabled);
524 this.can_change_channel_ = enabled;
529 * Sets the device target channel.
530 * @param {string} channel The name of the target channel.
531 * @param {boolean} isPowerwashAllowed True iff powerwash is allowed.
534 setChannel_: function(channel, isPowerwashAllowed) {
535 chrome.send('setChannel', [channel, isPowerwashAllowed]);
536 $('channel-change-confirmation').hidden = false;
537 $('channel-change-confirmation').textContent = loadTimeData.getStringF(
538 'channel-changed', this.channelTable_[channel].name);
539 this.updateTargetChannel_(channel);
543 * Sets the value of the "Build Date" field of the "More Info" section.
544 * @param {string} buildDate The date of the build.
547 setBuildDate_: function(buildDate) {
548 $('build-date-container').classList.remove('empty');
549 $('build-date').textContent = buildDate;
553 * Updates channel-change-page-container visibility according to
557 updateChannelChangePageContainerVisibility_: function() {
558 if (!this.isNewChannelSwitcherUI_()) {
559 $('channel-change-page-container').hidden = true;
562 $('channel-change-page-container').hidden =
563 !help.ChannelChangePage.isPageReady();
567 * Updates channel-changer dropdown visibility if |visible| is
568 * true and new channel switcher UI is disallowed.
569 * @param {boolean} visible True if channel-changer should be
570 * displayed, false otherwise.
573 updateChannelChangerContainerVisibility_: function(visible) {
574 if (this.isNewChannelSwitcherUI_()) {
575 $('channel-changer').hidden = true;
578 $('channel-changer').hidden = !visible;
582 * Sets the product label's alt text.
583 * @param {string} text The text to use for the image.
586 setProductLabelText_: function(text) {
587 $('product-label').setAttribute('alt', text);
591 HelpPage.setUpdateStatus = function(status, message) {
592 HelpPage.getInstance().setUpdateStatus_(status, message);
595 HelpPage.setProgress = function(progress) {
596 HelpPage.getInstance().setProgress_(progress);
599 HelpPage.setAndShowAllowedConnectionTypesMsg = function(message) {
600 HelpPage.getInstance().setAllowedConnectionTypesMsg_(message);
601 HelpPage.getInstance().showAllowedConnectionTypesMsg_(true);
604 HelpPage.showAllowedConnectionTypesMsg = function(visible) {
605 HelpPage.getInstance().showAllowedConnectionTypesMsg_(visible);
608 HelpPage.setPromotionState = function(state) {
609 HelpPage.getInstance().setPromotionState_(state);
612 HelpPage.setObsoleteSystem = function(obsolete) {
613 HelpPage.getInstance().setObsoleteSystem_(obsolete);
616 HelpPage.setObsoleteSystemEndOfTheLine = function(endOfTheLine) {
617 HelpPage.getInstance().setObsoleteSystemEndOfTheLine_(endOfTheLine);
620 HelpPage.setOSVersion = function(version) {
621 HelpPage.getInstance().setOSVersion_(version);
624 HelpPage.setOSFirmware = function(firmware) {
625 HelpPage.getInstance().setOSFirmware_(firmware);
628 HelpPage.updateIsEnterpriseManaged = function(isEnterpriseManaged) {
631 HelpPage.getInstance().updateIsEnterpriseManaged_(isEnterpriseManaged);
634 HelpPage.updateCurrentChannel = function(channel) {
637 HelpPage.getInstance().updateCurrentChannel_(channel);
640 HelpPage.updateTargetChannel = function(channel) {
643 HelpPage.getInstance().updateTargetChannel_(channel);
646 HelpPage.updateEnableReleaseChannel = function(enabled) {
647 HelpPage.getInstance().updateEnableReleaseChannel_(enabled);
650 HelpPage.setChannel = function(channel, isPowerwashAllowed) {
651 HelpPage.getInstance().setChannel_(channel, isPowerwashAllowed);
654 HelpPage.setBuildDate = function(buildDate) {
655 HelpPage.getInstance().setBuildDate_(buildDate);
658 HelpPage.setProductLabelText = function(text) {
659 HelpPage.getInstance().setProductLabelText_(text);