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 initializePage: function() {
57 Page.prototype.initializePage.call(this);
59 $('product-license').innerHTML = loadTimeData.getString('productLicense');
61 $('product-os-license').innerHTML =
62 loadTimeData.getString('productOsLicense');
65 var productTOS = $('product-tos');
67 productTOS.innerHTML = loadTimeData.getString('productTOS');
69 $('get-help').onclick = function() {
70 chrome.send('openHelpPage');
72 <if expr="_google_chrome">
73 $('report-issue').onclick = function() {
74 chrome.send('openFeedbackDialog');
78 this.maybeSetOnClick_($('more-info-expander'),
79 this.toggleMoreInfo_.bind(this));
81 this.maybeSetOnClick_($('promote'), function() {
82 chrome.send('promoteUpdater');
84 this.maybeSetOnClick_($('relaunch'), function() {
85 chrome.send('relaunchNow');
88 this.maybeSetOnClick_($('relaunch-and-powerwash'), function() {
89 chrome.send('relaunchAndPowerwash');
92 this.channelTable_ = {
94 'name': loadTimeData.getString('stable'),
95 'label': loadTimeData.getString('currentChannelStable'),
98 'name': loadTimeData.getString('beta'),
99 'label': loadTimeData.getString('currentChannelBeta')
102 'name': loadTimeData.getString('dev'),
103 'label': loadTimeData.getString('currentChannelDev')
107 this.maybeSetOnClick_($('about-done'), function() {
108 // Event listener for the close button when shown as an overlay.
109 PageManager.closeOverlay();
113 var channelChanger = $('channel-changer');
114 if (channelChanger) {
115 channelChanger.onchange = function(event) {
116 self.setChannel_(event.target.value, false);
121 // Add event listener for the check for and apply updates button.
122 this.maybeSetOnClick_($('request-update'), function() {
123 self.setUpdateStatus_('checking');
124 $('request-update').disabled = true;
125 chrome.send('requestUpdate');
128 $('change-channel').onclick = function() {
129 PageManager.showPageByName('channel-change-page', false);
132 var channelChangeDisallowedError = document.createElement('div');
133 channelChangeDisallowedError.className = 'channel-change-error-bubble';
135 var channelChangeDisallowedIcon = document.createElement('div');
136 channelChangeDisallowedIcon.classList.add('help-page-icon-large');
137 channelChangeDisallowedIcon.classList.add('channel-change-error-icon');
138 channelChangeDisallowedError.appendChild(channelChangeDisallowedIcon);
140 var channelChangeDisallowedText = document.createElement('div');
141 channelChangeDisallowedText.className = 'channel-change-error-text';
142 channelChangeDisallowedText.textContent =
143 loadTimeData.getString('channelChangeDisallowedMessage');
144 channelChangeDisallowedError.appendChild(channelChangeDisallowedText);
146 $('channel-change-disallowed-icon').onclick = function() {
147 PageManager.showBubble(channelChangeDisallowedError,
148 $('channel-change-disallowed-icon'),
150 cr.ui.ArrowLocation.TOP_END);
154 // Attempt to update.
155 chrome.send('onPageLoaded');
159 didClosePage: function() {
160 this.setMoreInfoVisible_(false);
164 * Sets the visible state of the 'More Info' section.
165 * @param {boolean} visible Whether the section should be visible.
168 setMoreInfoVisible_: function(visible) {
169 var moreInfo = $('more-info-container');
170 if (visible == moreInfo.classList.contains('visible'))
173 moreInfo.classList.toggle('visible', visible);
174 moreInfo.style.height = visible ? moreInfo.scrollHeight + 'px' : '';
175 moreInfo.addEventListener('webkitTransitionEnd', function(event) {
176 $('more-info-expander').textContent = visible ?
177 loadTimeData.getString('hideMoreInfo') :
178 loadTimeData.getString('showMoreInfo');
183 * Toggles the visible state of the 'More Info' section.
186 toggleMoreInfo_: function() {
187 var moreInfo = $('more-info-container');
188 this.setMoreInfoVisible_(!moreInfo.classList.contains('visible'));
192 * Assigns |method| to the onclick property of |el| if |el| exists.
193 * @param {HTMLElement} el The element on which to set the click handler.
194 * @param {Function} method The click handler.
197 maybeSetOnClick_: function(el, method) {
203 * @param {string} state The state of the update.
206 setUpdateImage_: function(state) {
207 $('update-status-icon').className = 'help-page-icon ' + state;
211 * @return {boolean} True, if new channel switcher UI is used,
215 isNewChannelSwitcherUI_: function() {
216 return !loadTimeData.valueExists('disableNewChannelSwitcherUI');
220 * @return {boolean} True if target and current channels are not null and
224 channelsDiffer_: function() {
225 var current = this.currentChannel_;
226 var target = this.targetChannel_;
227 return (current != null && target != null && current != target);
231 * @return {boolean} True if target channel is more stable than the current
232 * one, and false otherwise.
235 targetChannelIsMoreStable_: function() {
236 var current = this.currentChannel_;
237 var target = this.targetChannel_;
238 if (current == null || target == null)
240 var currentIndex = this.channelList_.indexOf(current);
241 var targetIndex = this.channelList_.indexOf(target);
242 if (currentIndex < 0 || targetIndex < 0)
244 return currentIndex < targetIndex;
248 * @param {string} status The status of the update.
249 * @param {string} message Failure message to display.
252 setUpdateStatus_: function(status, message) {
253 this.status_ = status;
254 this.message_ = message;
260 * Updates UI elements on the page according to current state.
263 updateUI_: function() {
264 var status = this.status_;
265 var message = this.message_;
266 var channel = this.targetChannel_;
268 if (this.channelList_.indexOf(channel) >= 0) {
269 $('current-channel').textContent = loadTimeData.getStringF(
270 'currentChannel', this.channelTable_[channel].label);
271 this.updateChannelChangePageContainerVisibility_();
278 $('update-status-message') &&
279 $('update-status-message').hidden) {
280 // Chrome has reached the end of the line on this system. The
281 // update-obsolete-system message is displayed. No other auto-update
282 // status should be displayed.
286 if (status == 'checking') {
287 this.setUpdateImage_('working');
288 $('update-status-message').innerHTML =
289 loadTimeData.getString('updateCheckStarted');
290 } else if (status == 'updating') {
291 this.setUpdateImage_('working');
292 if (this.channelsDiffer_()) {
293 $('update-status-message').innerHTML =
294 loadTimeData.getStringF('updatingChannelSwitch',
295 this.channelTable_[channel].label);
297 $('update-status-message').innerHTML =
298 loadTimeData.getStringF('updating');
300 } else if (status == 'nearly_updated') {
301 this.setUpdateImage_('up-to-date');
302 if (this.channelsDiffer_()) {
303 $('update-status-message').innerHTML =
304 loadTimeData.getString('successfulChannelSwitch');
306 $('update-status-message').innerHTML =
307 loadTimeData.getString('updateAlmostDone');
309 } else if (status == 'updated') {
310 this.setUpdateImage_('up-to-date');
311 $('update-status-message').innerHTML =
312 loadTimeData.getString('upToDate');
313 } else if (status == 'failed') {
314 this.setUpdateImage_('failed');
315 $('update-status-message').innerHTML = message;
318 // Following invariant must be established at the end of this function:
319 // { ~$('relaunch_and_powerwash').hidden -> $('relaunch').hidden }
320 var relaunchAndPowerwashHidden = true;
321 if ($('relaunch-and-powerwash')) {
322 // It's allowed to do powerwash only for customer devices,
323 // when user explicitly decides to update to a more stable
325 relaunchAndPowerwashHidden =
326 !this.targetChannelIsMoreStable_() || status != 'nearly_updated';
327 $('relaunch-and-powerwash').hidden = relaunchAndPowerwashHidden;
331 // Only enable the update button if it hasn't been used yet or the
332 // status isn't 'updated'.
333 if (!$('request-update').disabled || status != 'updated') {
334 // Disable the button if an update is already in progress.
335 $('request-update').disabled =
336 ['checking', 'updating', 'nearly_updated'].indexOf(status) > -1;
340 var container = $('update-status-container');
342 container.hidden = status == 'disabled';
343 $('relaunch').hidden =
344 (status != 'nearly_updated') || !relaunchAndPowerwashHidden;
347 // Assume the "updated" status is stale if we haven't checked yet.
348 if (status == 'updated' && !$('request-update').disabled)
349 container.hidden = true;
351 // Hide the request update button if auto-updating is disabled or
352 // a relaunch button is showing.
353 $('request-update').hidden = status == 'disabled' ||
354 !$('relaunch').hidden || !relaunchAndPowerwashHidden;
358 $('update-percentage').hidden = status != 'updating';
363 * @param {number} progress The percent completion.
366 setProgress_: function(progress) {
367 $('update-percentage').innerHTML = progress + '%';
371 * @param {string} message The allowed connection types message.
374 setAllowedConnectionTypesMsg_: function(message) {
375 $('allowed-connection-types-message').innerText = message;
379 * @param {boolean} visible Whether to show the message.
382 showAllowedConnectionTypesMsg_: function(visible) {
383 $('allowed-connection-types-message').hidden = !visible;
387 * @param {string} state The promote state to set.
390 setPromotionState_: function(state) {
391 if (state == 'hidden') {
392 $('promote').hidden = true;
393 } else if (state == 'enabled') {
394 $('promote').disabled = false;
395 $('promote').hidden = false;
396 } else if (state == 'disabled') {
397 $('promote').disabled = true;
398 $('promote').hidden = false;
403 * @param {boolean} obsolete Whether the system is obsolete.
406 setObsoleteSystem_: function(obsolete) {
407 if (cr.isMac && $('update-obsolete-system-container')) {
408 $('update-obsolete-system-container').hidden = !obsolete;
413 * @param {boolean} endOfTheLine Whether the train has rolled into
417 setObsoleteSystemEndOfTheLine_: function(endOfTheLine) {
419 $('update-obsolete-system-container') &&
420 !$('update-obsolete-system-container').hidden &&
421 $('update-status-message')) {
422 $('update-status-message').hidden = endOfTheLine;
424 this.setUpdateImage_('failed');
430 * @param {string} version Version of Chrome OS.
433 setOSVersion_: function(version) {
435 console.error('OS version unsupported on non-CrOS');
437 $('os-version').parentNode.hidden = (version == '');
438 $('os-version').textContent = version;
442 * @param {string} firmware Firmware on Chrome OS.
445 setOSFirmware_: function(firmware) {
447 console.error('OS firmware unsupported on non-CrOS');
449 $('firmware').parentNode.hidden = (firmware == '');
450 $('firmware').textContent = firmware;
454 * Updates page UI according to device owhership policy.
455 * @param {boolean} isEnterpriseManaged True if the device is
456 * enterprise managed.
459 updateIsEnterpriseManaged_: function(isEnterpriseManaged) {
460 help.ChannelChangePage.updateIsEnterpriseManaged(isEnterpriseManaged);
465 * Updates name of the current channel, i.e. the name of the
466 * channel the device is currently on.
467 * @param {string} channel The name of the current channel.
470 updateCurrentChannel_: function(channel) {
471 if (this.channelList_.indexOf(channel) < 0)
473 this.currentChannel_ = channel;
474 help.ChannelChangePage.updateCurrentChannel(channel);
479 * Updates name of the target channel, i.e. the name of the
480 * channel the device is supposed to be.
481 * @param {string} channel The name of the target channel.
484 updateTargetChannel_: function(channel) {
485 if (this.channelList_.indexOf(channel) < 0)
487 this.targetChannel_ = channel;
488 help.ChannelChangePage.updateTargetChannel(channel);
493 * @param {boolean} enabled True if the release channel can be enabled.
496 updateEnableReleaseChannel_: function(enabled) {
497 this.updateChannelChangerContainerVisibility_(enabled);
498 $('change-channel').disabled = !enabled;
499 $('channel-change-disallowed-icon').hidden = enabled;
503 * Sets the device target channel.
504 * @param {string} channel The name of the target channel.
505 * @param {boolean} isPowerwashAllowed True iff powerwash is allowed.
508 setChannel_: function(channel, isPowerwashAllowed) {
509 chrome.send('setChannel', [channel, isPowerwashAllowed]);
510 $('channel-change-confirmation').hidden = false;
511 $('channel-change-confirmation').textContent = loadTimeData.getStringF(
512 'channel-changed', this.channelTable_[channel].name);
513 this.updateTargetChannel_(channel);
517 * Sets the value of the "Build Date" field of the "More Info" section.
518 * @param {string} buildDate The date of the build.
521 setBuildDate_: function(buildDate) {
522 $('build-date-container').classList.remove('empty');
523 $('build-date').textContent = buildDate;
527 * Updates channel-change-page-container visibility according to
531 updateChannelChangePageContainerVisibility_: function() {
532 if (!this.isNewChannelSwitcherUI_()) {
533 $('channel-change-page-container').hidden = true;
536 $('channel-change-page-container').hidden =
537 !help.ChannelChangePage.isPageReady();
541 * Updates channel-changer dropdown visibility if |visible| is
542 * true and new channel switcher UI is disallowed.
543 * @param {boolean} visible True if channel-changer should be
544 * displayed, false otherwise.
547 updateChannelChangerContainerVisibility_: function(visible) {
548 if (this.isNewChannelSwitcherUI_()) {
549 $('channel-changer').hidden = true;
552 $('channel-changer').hidden = !visible;
556 HelpPage.setUpdateStatus = function(status, message) {
557 HelpPage.getInstance().setUpdateStatus_(status, message);
560 HelpPage.setProgress = function(progress) {
561 HelpPage.getInstance().setProgress_(progress);
564 HelpPage.setAndShowAllowedConnectionTypesMsg = function(message) {
565 HelpPage.getInstance().setAllowedConnectionTypesMsg_(message);
566 HelpPage.getInstance().showAllowedConnectionTypesMsg_(true);
569 HelpPage.showAllowedConnectionTypesMsg = function(visible) {
570 HelpPage.getInstance().showAllowedConnectionTypesMsg_(visible);
573 HelpPage.setPromotionState = function(state) {
574 HelpPage.getInstance().setPromotionState_(state);
577 HelpPage.setObsoleteSystem = function(obsolete) {
578 HelpPage.getInstance().setObsoleteSystem_(obsolete);
581 HelpPage.setObsoleteSystemEndOfTheLine = function(endOfTheLine) {
582 HelpPage.getInstance().setObsoleteSystemEndOfTheLine_(endOfTheLine);
585 HelpPage.setOSVersion = function(version) {
586 HelpPage.getInstance().setOSVersion_(version);
589 HelpPage.setOSFirmware = function(firmware) {
590 HelpPage.getInstance().setOSFirmware_(firmware);
593 HelpPage.updateIsEnterpriseManaged = function(isEnterpriseManaged) {
596 HelpPage.getInstance().updateIsEnterpriseManaged_(isEnterpriseManaged);
599 HelpPage.updateCurrentChannel = function(channel) {
602 HelpPage.getInstance().updateCurrentChannel_(channel);
605 HelpPage.updateTargetChannel = function(channel) {
608 HelpPage.getInstance().updateTargetChannel_(channel);
611 HelpPage.updateEnableReleaseChannel = function(enabled) {
612 HelpPage.getInstance().updateEnableReleaseChannel_(enabled);
615 HelpPage.setChannel = function(channel, isPowerwashAllowed) {
616 HelpPage.getInstance().setChannel_(channel, isPowerwashAllowed);
619 HelpPage.setBuildDate = function(buildDate) {
620 HelpPage.getInstance().setBuildDate_(buildDate);