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.className =
143 'help-page-icon 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 regulatory label if/when the image loads.
160 $('regulatory-label').onload = function() {
161 $('regulatory-label-container').hidden = false;
165 var logo = $('product-logo');
166 logo.onclick = function(e) {
167 logo.classList.remove('spin');
168 setTimeout(function() { logo.classList.add('spin'); }, 0);
171 // Attempt to update.
172 chrome.send('onPageLoaded');
176 didClosePage: function() {
177 this.setMoreInfoVisible_(false);
181 * Sets the visible state of the 'More Info' section.
182 * @param {boolean} visible Whether the section should be visible.
185 setMoreInfoVisible_: function(visible) {
186 var moreInfo = $('more-info-container');
187 if (!moreInfo || visible == moreInfo.classList.contains('visible'))
190 moreInfo.classList.toggle('visible', visible);
191 moreInfo.style.height = visible ? moreInfo.scrollHeight + 'px' : '';
192 moreInfo.addEventListener('webkitTransitionEnd', function(event) {
193 $('more-info-expander').textContent = visible ?
194 loadTimeData.getString('hideMoreInfo') :
195 loadTimeData.getString('showMoreInfo');
200 * Toggles the visible state of the 'More Info' section.
203 toggleMoreInfo_: function() {
204 var moreInfo = $('more-info-container');
205 this.setMoreInfoVisible_(!moreInfo.classList.contains('visible'));
209 * Assigns |method| to the onclick property of |el| if |el| exists.
210 * @param {HTMLElement} el The element on which to set the click handler.
211 * @param {Function} method The click handler.
214 maybeSetOnClick_: function(el, method) {
220 * @param {string} state The state of the update.
223 setUpdateImage_: function(state) {
224 $('update-status-icon').className = 'help-page-icon ' + state;
228 * @return {boolean} True, if new channel switcher UI is used,
232 isNewChannelSwitcherUI_: function() {
233 return !loadTimeData.valueExists('disableNewChannelSwitcherUI');
237 * @return {boolean} True if target and current channels are not null and
241 channelsDiffer_: function() {
242 var current = this.currentChannel_;
243 var target = this.targetChannel_;
244 return (current != null && target != null && current != target);
248 * @return {boolean} True if target channel is more stable than the current
249 * one, and false otherwise.
252 targetChannelIsMoreStable_: function() {
253 var current = this.currentChannel_;
254 var target = this.targetChannel_;
255 if (current == null || target == null)
257 var currentIndex = this.channelList_.indexOf(current);
258 var targetIndex = this.channelList_.indexOf(target);
259 if (currentIndex < 0 || targetIndex < 0)
261 return currentIndex < targetIndex;
265 * @param {string} status The status of the update.
266 * @param {string} message Failure message to display.
269 setUpdateStatus_: function(status, message) {
270 this.status_ = status;
271 this.message_ = message;
277 * Updates UI elements on the page according to current state.
280 updateUI_: function() {
281 var status = this.status_;
282 var message = this.message_;
283 var channel = this.targetChannel_;
285 if (this.channelList_.indexOf(channel) >= 0) {
286 $('current-channel').textContent = loadTimeData.getStringF(
287 'currentChannel', this.channelTable_[channel].label);
288 this.updateChannelChangePageContainerVisibility_();
295 $('update-status-message') &&
296 $('update-status-message').hidden) {
297 // Chrome has reached the end of the line on this system. The
298 // update-obsolete-system message is displayed. No other auto-update
299 // status should be displayed.
303 if (status == 'checking') {
304 this.setUpdateImage_('working');
305 $('update-status-message').innerHTML =
306 loadTimeData.getString('updateCheckStarted');
307 } else if (status == 'updating') {
308 this.setUpdateImage_('working');
309 if (this.channelsDiffer_()) {
310 $('update-status-message').innerHTML =
311 loadTimeData.getStringF('updatingChannelSwitch',
312 this.channelTable_[channel].label);
314 $('update-status-message').innerHTML =
315 loadTimeData.getStringF('updating');
317 } else if (status == 'nearly_updated') {
318 this.setUpdateImage_('up-to-date');
319 if (this.channelsDiffer_()) {
320 $('update-status-message').innerHTML =
321 loadTimeData.getString('successfulChannelSwitch');
323 $('update-status-message').innerHTML =
324 loadTimeData.getString('updateAlmostDone');
326 } else if (status == 'updated') {
327 this.setUpdateImage_('up-to-date');
328 $('update-status-message').innerHTML =
329 loadTimeData.getString('upToDate');
330 } else if (status == 'failed') {
331 this.setUpdateImage_('failed');
332 $('update-status-message').innerHTML = message;
336 $('change-channel').disabled = !this.can_change_channel_ ||
337 status == 'nearly_updated';
338 $('channel-change-disallowed-icon').hidden = this.can_change_channel_;
341 // Following invariant must be established at the end of this function:
342 // { ~$('relaunch_and_powerwash').hidden -> $('relaunch').hidden }
343 var relaunchAndPowerwashHidden = true;
344 if ($('relaunch-and-powerwash')) {
345 // It's allowed to do powerwash only for customer devices,
346 // when user explicitly decides to update to a more stable
348 relaunchAndPowerwashHidden =
349 !this.targetChannelIsMoreStable_() || status != 'nearly_updated';
350 $('relaunch-and-powerwash').hidden = relaunchAndPowerwashHidden;
354 // Only enable the update button if it hasn't been used yet or the
355 // status isn't 'updated'.
356 if (!$('request-update').disabled || status != 'updated') {
357 // Disable the button if an update is already in progress.
358 $('request-update').disabled =
359 ['checking', 'updating', 'nearly_updated'].indexOf(status) > -1;
363 var container = $('update-status-container');
365 container.hidden = status == 'disabled';
366 $('relaunch').hidden =
367 (status != 'nearly_updated') || !relaunchAndPowerwashHidden;
370 // Assume the "updated" status is stale if we haven't checked yet.
371 if (status == 'updated' && !$('request-update').disabled)
372 container.hidden = true;
374 // Hide the request update button if auto-updating is disabled or
375 // a relaunch button is showing.
376 $('request-update').hidden = status == 'disabled' ||
377 !$('relaunch').hidden || !relaunchAndPowerwashHidden;
381 $('update-percentage').hidden = status != 'updating';
386 * @param {number} progress The percent completion.
389 setProgress_: function(progress) {
390 $('update-percentage').innerHTML = progress + '%';
394 * @param {string} message The allowed connection types message.
397 setAllowedConnectionTypesMsg_: function(message) {
398 $('allowed-connection-types-message').innerText = message;
402 * @param {boolean} visible Whether to show the message.
405 showAllowedConnectionTypesMsg_: function(visible) {
406 $('allowed-connection-types-message').hidden = !visible;
410 * @param {string} state The promote state to set.
413 setPromotionState_: function(state) {
414 if (state == 'hidden') {
415 $('promote').hidden = true;
416 } else if (state == 'enabled') {
417 $('promote').disabled = false;
418 $('promote').hidden = false;
419 } else if (state == 'disabled') {
420 $('promote').disabled = true;
421 $('promote').hidden = false;
426 * @param {boolean} obsolete Whether the system is obsolete.
429 setObsoleteSystem_: function(obsolete) {
430 if (cr.isMac && $('update-obsolete-system-container')) {
431 $('update-obsolete-system-container').hidden = !obsolete;
436 * @param {boolean} endOfTheLine Whether the train has rolled into
440 setObsoleteSystemEndOfTheLine_: function(endOfTheLine) {
442 $('update-obsolete-system-container') &&
443 !$('update-obsolete-system-container').hidden &&
444 $('update-status-message')) {
445 $('update-status-message').hidden = endOfTheLine;
447 this.setUpdateImage_('failed');
453 * @param {string} version Version of Chrome OS.
456 setOSVersion_: function(version) {
458 console.error('OS version unsupported on non-CrOS');
460 $('os-version').parentNode.hidden = (version == '');
461 $('os-version').textContent = version;
465 * @param {string} firmware Firmware on Chrome OS.
468 setOSFirmware_: function(firmware) {
470 console.error('OS firmware unsupported on non-CrOS');
472 $('firmware').parentNode.hidden = (firmware == '');
473 $('firmware').textContent = firmware;
477 * Updates page UI according to device owhership policy.
478 * @param {boolean} isEnterpriseManaged True if the device is
479 * enterprise managed.
482 updateIsEnterpriseManaged_: function(isEnterpriseManaged) {
483 help.ChannelChangePage.updateIsEnterpriseManaged(isEnterpriseManaged);
488 * Updates name of the current channel, i.e. the name of the
489 * channel the device is currently on.
490 * @param {string} channel The name of the current channel.
493 updateCurrentChannel_: function(channel) {
494 if (this.channelList_.indexOf(channel) < 0)
496 this.currentChannel_ = channel;
497 help.ChannelChangePage.updateCurrentChannel(channel);
502 * Updates name of the target channel, i.e. the name of the
503 * channel the device is supposed to be.
504 * @param {string} channel The name of the target channel.
507 updateTargetChannel_: function(channel) {
508 if (this.channelList_.indexOf(channel) < 0)
510 this.targetChannel_ = channel;
511 help.ChannelChangePage.updateTargetChannel(channel);
516 * @param {boolean} enabled True if the release channel can be enabled.
519 updateEnableReleaseChannel_: function(enabled) {
520 this.updateChannelChangerContainerVisibility_(enabled);
521 this.can_change_channel_ = enabled;
526 * Sets the device target channel.
527 * @param {string} channel The name of the target channel.
528 * @param {boolean} isPowerwashAllowed True iff powerwash is allowed.
531 setChannel_: function(channel, isPowerwashAllowed) {
532 chrome.send('setChannel', [channel, isPowerwashAllowed]);
533 $('channel-change-confirmation').hidden = false;
534 $('channel-change-confirmation').textContent = loadTimeData.getStringF(
535 'channel-changed', this.channelTable_[channel].name);
536 this.updateTargetChannel_(channel);
540 * Sets the value of the "Build Date" field of the "More Info" section.
541 * @param {string} buildDate The date of the build.
544 setBuildDate_: function(buildDate) {
545 $('build-date-container').classList.remove('empty');
546 $('build-date').textContent = buildDate;
550 * Updates channel-change-page-container visibility according to
554 updateChannelChangePageContainerVisibility_: function() {
555 if (!this.isNewChannelSwitcherUI_()) {
556 $('channel-change-page-container').hidden = true;
559 $('channel-change-page-container').hidden =
560 !help.ChannelChangePage.isPageReady();
564 * Updates channel-changer dropdown visibility if |visible| is
565 * true and new channel switcher UI is disallowed.
566 * @param {boolean} visible True if channel-changer should be
567 * displayed, false otherwise.
570 updateChannelChangerContainerVisibility_: function(visible) {
571 if (this.isNewChannelSwitcherUI_()) {
572 $('channel-changer').hidden = true;
575 $('channel-changer').hidden = !visible;
579 * Sets the regulatory label's source.
580 * @param {string} path The path to use for the image.
583 setRegulatoryLabelPath_: function(path) {
584 $('regulatory-label').src = path;
588 * Sets the regulatory label's alt text.
589 * @param {string} text The text to use for the image.
592 setRegulatoryLabelText_: function(text) {
593 $('regulatory-label').alt = text;
597 HelpPage.setUpdateStatus = function(status, message) {
598 HelpPage.getInstance().setUpdateStatus_(status, message);
601 HelpPage.setProgress = function(progress) {
602 HelpPage.getInstance().setProgress_(progress);
605 HelpPage.setAndShowAllowedConnectionTypesMsg = function(message) {
606 HelpPage.getInstance().setAllowedConnectionTypesMsg_(message);
607 HelpPage.getInstance().showAllowedConnectionTypesMsg_(true);
610 HelpPage.showAllowedConnectionTypesMsg = function(visible) {
611 HelpPage.getInstance().showAllowedConnectionTypesMsg_(visible);
614 HelpPage.setPromotionState = function(state) {
615 HelpPage.getInstance().setPromotionState_(state);
618 HelpPage.setObsoleteSystem = function(obsolete) {
619 HelpPage.getInstance().setObsoleteSystem_(obsolete);
622 HelpPage.setObsoleteSystemEndOfTheLine = function(endOfTheLine) {
623 HelpPage.getInstance().setObsoleteSystemEndOfTheLine_(endOfTheLine);
626 HelpPage.setOSVersion = function(version) {
627 HelpPage.getInstance().setOSVersion_(version);
630 HelpPage.setOSFirmware = function(firmware) {
631 HelpPage.getInstance().setOSFirmware_(firmware);
634 HelpPage.updateIsEnterpriseManaged = function(isEnterpriseManaged) {
637 HelpPage.getInstance().updateIsEnterpriseManaged_(isEnterpriseManaged);
640 HelpPage.updateCurrentChannel = function(channel) {
643 HelpPage.getInstance().updateCurrentChannel_(channel);
646 HelpPage.updateTargetChannel = function(channel) {
649 HelpPage.getInstance().updateTargetChannel_(channel);
652 HelpPage.updateEnableReleaseChannel = function(enabled) {
653 HelpPage.getInstance().updateEnableReleaseChannel_(enabled);
656 HelpPage.setChannel = function(channel, isPowerwashAllowed) {
657 HelpPage.getInstance().setChannel_(channel, isPowerwashAllowed);
660 HelpPage.setBuildDate = function(buildDate) {
661 HelpPage.getInstance().setBuildDate_(buildDate);
664 HelpPage.setRegulatoryLabelPath = function(path) {
665 assert(cr.isChromeOS);
666 HelpPage.getInstance().setRegulatoryLabelPath_(path);
669 HelpPage.setRegulatoryLabelText = function(text) {
670 assert(cr.isChromeOS);
671 HelpPage.getInstance().setRegulatoryLabelText_(text);