Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / help / help_page.js
blobd3d53dc50c5856b7306ddfbf3c1c70faa7e88e57
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;
9   /**
10    * Encapsulated handling of the About page. Called 'help' internally to avoid
11    * confusion with generic AboutUI (about:memory, about:sandbox, etc.).
12    */
13   function HelpPage() {
14     var id = loadTimeData.valueExists('aboutOverlayTabTitle') ?
15       'aboutOverlayTabTitle' : 'aboutTitle';
16     Page.call(this, 'help', loadTimeData.getString(id), 'help-page');
17   }
19   cr.addSingletonGetter(HelpPage);
21   HelpPage.prototype = {
22     __proto__: Page.prototype,
24     /**
25      * List of the channel names. Should be ordered in increasing level of
26      * stability.
27      * @private
28      */
29     channelList_: ['dev-channel', 'beta-channel', 'stable-channel'],
31     /**
32      * Name of the channel the device is currently on.
33      * @private
34      */
35     currentChannel_: null,
37     /**
38      * Name of the channel the device is supposed to be on.
39      * @private
40      */
41     targetChannel_: null,
43     /**
44      * Last status received from the version updater.
45      * @private
46      */
47     status_: null,
49     /**
50      * Last message received from the version updater.
51      * @private
52      */
53     message_: null,
55     /**
56      * True if user is allowed to change channels, false otherwise.
57      * @private
58      */
59     can_change_channel_: false,
61     /** @override */
62     initializePage: function() {
63       Page.prototype.initializePage.call(this);
65       $('product-license').innerHTML = loadTimeData.getString('productLicense');
66       if (cr.isChromeOS) {
67         $('product-os-license').innerHTML =
68             loadTimeData.getString('productOsLicense');
69       }
71       var productTOS = $('product-tos');
72       if (productTOS)
73         productTOS.innerHTML = loadTimeData.getString('productTOS');
75       $('get-help').onclick = function() {
76         chrome.send('openHelpPage');
77       };
78 <if expr="_google_chrome">
79       $('report-issue').onclick = function() {
80         chrome.send('openFeedbackDialog');
81       };
82 </if>
84       this.maybeSetOnClick_($('more-info-expander'),
85           this.toggleMoreInfo_.bind(this));
87       this.maybeSetOnClick_($('promote'), function() {
88         chrome.send('promoteUpdater');
89       });
90       this.maybeSetOnClick_($('relaunch'), function() {
91         chrome.send('relaunchNow');
92       });
93       if (cr.isChromeOS) {
94         this.maybeSetOnClick_($('relaunch-and-powerwash'), function() {
95           chrome.send('relaunchAndPowerwash');
96         });
98         this.channelTable_ = {
99           'stable-channel': {
100             'name': loadTimeData.getString('stable'),
101             'label': loadTimeData.getString('currentChannelStable'),
102           },
103           'beta-channel': {
104             'name': loadTimeData.getString('beta'),
105             'label': loadTimeData.getString('currentChannelBeta')
106           },
107           'dev-channel': {
108             'name': loadTimeData.getString('dev'),
109             'label': loadTimeData.getString('currentChannelDev')
110           }
111         };
112       }
113       this.maybeSetOnClick_($('about-done'), function() {
114         // Event listener for the close button when shown as an overlay.
115         PageManager.closeOverlay();
116       });
118       var self = this;
119       var channelChanger = $('channel-changer');
120       if (channelChanger) {
121         channelChanger.onchange = function(event) {
122           self.setChannel_(event.target.value, false);
123         };
124       }
126       if (cr.isChromeOS) {
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');
132         });
134         $('change-channel').onclick = function() {
135           PageManager.showPageByName('channel-change-page', false);
136         };
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'),
155                                  $('help-container'),
156                                  cr.ui.ArrowLocation.TOP_END);
157         };
159         // Unhide the regulatory label if/when the image loads.
160         $('regulatory-label').onload = function() {
161           $('regulatory-label-container').hidden = false;
162         };
163       }
165       var logo = $('product-logo');
166       logo.onclick = function(e) {
167         logo.classList.remove('spin');
168         setTimeout(function() { logo.classList.add('spin'); }, 0);
169       };
171       // Attempt to update.
172       chrome.send('onPageLoaded');
173     },
175     /** @override */
176     didClosePage: function() {
177       this.setMoreInfoVisible_(false);
178     },
180     /**
181      * Sets the visible state of the 'More Info' section.
182      * @param {boolean} visible Whether the section should be visible.
183      * @private
184      */
185     setMoreInfoVisible_: function(visible) {
186       var moreInfo = $('more-info-container');
187       if (!moreInfo || visible == moreInfo.classList.contains('visible'))
188         return;
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');
196       });
197     },
199     /**
200      * Toggles the visible state of the 'More Info' section.
201      * @private
202      */
203     toggleMoreInfo_: function() {
204       var moreInfo = $('more-info-container');
205       this.setMoreInfoVisible_(!moreInfo.classList.contains('visible'));
206     },
208     /**
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.
212      * @private
213      */
214     maybeSetOnClick_: function(el, method) {
215       if (el)
216         el.onclick = method;
217     },
219     /**
220      * @param {string} state The state of the update.
221      * private
222      */
223     setUpdateImage_: function(state) {
224       $('update-status-icon').className = 'help-page-icon ' + state;
225     },
227     /**
228      * @return {boolean} True, if new channel switcher UI is used,
229      *    false otherwise.
230      * @private
231      */
232     isNewChannelSwitcherUI_: function() {
233       return !loadTimeData.valueExists('disableNewChannelSwitcherUI');
234     },
236     /**
237      * @return {boolean} True if target and current channels are not null and
238      *     not equal.
239      * @private
240      */
241     channelsDiffer_: function() {
242       var current = this.currentChannel_;
243       var target = this.targetChannel_;
244       return (current != null && target != null && current != target);
245     },
247     /**
248      * @return {boolean} True if target channel is more stable than the current
249      *     one, and false otherwise.
250      * @private
251      */
252     targetChannelIsMoreStable_: function() {
253       var current = this.currentChannel_;
254       var target = this.targetChannel_;
255       if (current == null || target == null)
256         return false;
257       var currentIndex = this.channelList_.indexOf(current);
258       var targetIndex = this.channelList_.indexOf(target);
259       if (currentIndex < 0 || targetIndex < 0)
260         return false;
261       return currentIndex < targetIndex;
262     },
264     /**
265      * @param {string} status The status of the update.
266      * @param {string} message Failure message to display.
267      * @private
268      */
269     setUpdateStatus_: function(status, message) {
270       this.status_ = status;
271       this.message_ = message;
273       this.updateUI_();
274     },
276     /**
277       * Updates UI elements on the page according to current state.
278       * @private
279       */
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_();
289       }
291       if (status == null)
292         return;
294       if (cr.isMac &&
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.
300         return;
301       }
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);
313         } else {
314           $('update-status-message').innerHTML =
315               loadTimeData.getStringF('updating');
316         }
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');
322         } else {
323           $('update-status-message').innerHTML =
324               loadTimeData.getString('updateAlmostDone');
325         }
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;
333       }
335       if (cr.isChromeOS) {
336         $('change-channel').disabled = !this.can_change_channel_ ||
337             status == 'nearly_updated';
338         $('channel-change-disallowed-icon').hidden = this.can_change_channel_;
339       }
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
347         // channel.
348         relaunchAndPowerwashHidden =
349             !this.targetChannelIsMoreStable_() || status != 'nearly_updated';
350         $('relaunch-and-powerwash').hidden = relaunchAndPowerwashHidden;
351       }
353       if (cr.isChromeOS) {
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;
360         }
361       }
363       var container = $('update-status-container');
364       if (container) {
365         container.hidden = status == 'disabled';
366         $('relaunch').hidden =
367             (status != 'nearly_updated') || !relaunchAndPowerwashHidden;
369         if (cr.isChromeOS) {
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;
378         }
380         if (!cr.isMac)
381           $('update-percentage').hidden = status != 'updating';
382       }
383     },
385     /**
386      * @param {number} progress The percent completion.
387      * @private
388      */
389     setProgress_: function(progress) {
390       $('update-percentage').innerHTML = progress + '%';
391     },
393     /**
394      * @param {string} message The allowed connection types message.
395      * @private
396      */
397     setAllowedConnectionTypesMsg_: function(message) {
398       $('allowed-connection-types-message').innerText = message;
399     },
401     /**
402      * @param {boolean} visible Whether to show the message.
403      * @private
404      */
405     showAllowedConnectionTypesMsg_: function(visible) {
406       $('allowed-connection-types-message').hidden = !visible;
407     },
409     /**
410      * @param {string} state The promote state to set.
411      * @private
412      */
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;
422       }
423     },
425     /**
426      * @param {boolean} obsolete Whether the system is obsolete.
427      * @private
428      */
429     setObsoleteSystem_: function(obsolete) {
430       if (cr.isMac && $('update-obsolete-system-container')) {
431         $('update-obsolete-system-container').hidden = !obsolete;
432       }
433     },
435     /**
436      * @param {boolean} endOfTheLine Whether the train has rolled into
437      *     the station.
438      * @private
439      */
440     setObsoleteSystemEndOfTheLine_: function(endOfTheLine) {
441       if (cr.isMac &&
442           $('update-obsolete-system-container') &&
443           !$('update-obsolete-system-container').hidden &&
444           $('update-status-message')) {
445         $('update-status-message').hidden = endOfTheLine;
446         if (endOfTheLine) {
447           this.setUpdateImage_('failed');
448         }
449       }
450     },
452     /**
453      * @param {string} version Version of Chrome OS.
454      * @private
455      */
456     setOSVersion_: function(version) {
457       if (!cr.isChromeOS)
458         console.error('OS version unsupported on non-CrOS');
460       $('os-version').parentNode.hidden = (version == '');
461       $('os-version').textContent = version;
462     },
464     /**
465      * @param {string} firmware Firmware on Chrome OS.
466      * @private
467      */
468     setOSFirmware_: function(firmware) {
469       if (!cr.isChromeOS)
470         console.error('OS firmware unsupported on non-CrOS');
472       $('firmware').parentNode.hidden = (firmware == '');
473       $('firmware').textContent = firmware;
474     },
476     /**
477      * Updates page UI according to device owhership policy.
478      * @param {boolean} isEnterpriseManaged True if the device is
479      *     enterprise managed.
480      * @private
481      */
482     updateIsEnterpriseManaged_: function(isEnterpriseManaged) {
483       help.ChannelChangePage.updateIsEnterpriseManaged(isEnterpriseManaged);
484       this.updateUI_();
485     },
487     /**
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.
491      * @private
492      */
493     updateCurrentChannel_: function(channel) {
494       if (this.channelList_.indexOf(channel) < 0)
495         return;
496       this.currentChannel_ = channel;
497       help.ChannelChangePage.updateCurrentChannel(channel);
498       this.updateUI_();
499     },
501     /**
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.
505      * @private
506      */
507     updateTargetChannel_: function(channel) {
508       if (this.channelList_.indexOf(channel) < 0)
509         return;
510       this.targetChannel_ = channel;
511       help.ChannelChangePage.updateTargetChannel(channel);
512       this.updateUI_();
513     },
515     /**
516      * @param {boolean} enabled True if the release channel can be enabled.
517      * @private
518      */
519     updateEnableReleaseChannel_: function(enabled) {
520       this.updateChannelChangerContainerVisibility_(enabled);
521       this.can_change_channel_ = enabled;
522       this.updateUI_();
523     },
525     /**
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.
529      * @private
530      */
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);
537     },
539     /**
540      * Sets the value of the "Build Date" field of the "More Info" section.
541      * @param {string} buildDate The date of the build.
542      * @private
543      */
544     setBuildDate_: function(buildDate) {
545       $('build-date-container').classList.remove('empty');
546       $('build-date').textContent = buildDate;
547     },
549     /**
550      * Updates channel-change-page-container visibility according to
551      * internal state.
552      * @private
553      */
554     updateChannelChangePageContainerVisibility_: function() {
555       if (!this.isNewChannelSwitcherUI_()) {
556         $('channel-change-page-container').hidden = true;
557         return;
558       }
559       $('channel-change-page-container').hidden =
560           !help.ChannelChangePage.isPageReady();
561     },
563     /**
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.
568      * @private
569      */
570     updateChannelChangerContainerVisibility_: function(visible) {
571       if (this.isNewChannelSwitcherUI_()) {
572         $('channel-changer').hidden = true;
573         return;
574       }
575       $('channel-changer').hidden = !visible;
576     },
578     /**
579      * Sets the regulatory label's source.
580      * @param {string} path The path to use for the image.
581      * @private
582      */
583     setRegulatoryLabelPath_: function(path) {
584       $('regulatory-label').src = path;
585     },
587     /**
588      * Sets the regulatory label's alt text.
589      * @param {string} text The text to use for the image.
590      * @private
591      */
592     setRegulatoryLabelText_: function(text) {
593       $('regulatory-label').alt = text;
594     },
595   };
597   HelpPage.setUpdateStatus = function(status, message) {
598     HelpPage.getInstance().setUpdateStatus_(status, message);
599   };
601   HelpPage.setProgress = function(progress) {
602     HelpPage.getInstance().setProgress_(progress);
603   };
605   HelpPage.setAndShowAllowedConnectionTypesMsg = function(message) {
606     HelpPage.getInstance().setAllowedConnectionTypesMsg_(message);
607     HelpPage.getInstance().showAllowedConnectionTypesMsg_(true);
608   };
610   HelpPage.showAllowedConnectionTypesMsg = function(visible) {
611     HelpPage.getInstance().showAllowedConnectionTypesMsg_(visible);
612   };
614   HelpPage.setPromotionState = function(state) {
615     HelpPage.getInstance().setPromotionState_(state);
616   };
618   HelpPage.setObsoleteSystem = function(obsolete) {
619     HelpPage.getInstance().setObsoleteSystem_(obsolete);
620   };
622   HelpPage.setObsoleteSystemEndOfTheLine = function(endOfTheLine) {
623     HelpPage.getInstance().setObsoleteSystemEndOfTheLine_(endOfTheLine);
624   };
626   HelpPage.setOSVersion = function(version) {
627     HelpPage.getInstance().setOSVersion_(version);
628   };
630   HelpPage.setOSFirmware = function(firmware) {
631     HelpPage.getInstance().setOSFirmware_(firmware);
632   };
634   HelpPage.updateIsEnterpriseManaged = function(isEnterpriseManaged) {
635     if (!cr.isChromeOS)
636       return;
637     HelpPage.getInstance().updateIsEnterpriseManaged_(isEnterpriseManaged);
638   };
640   HelpPage.updateCurrentChannel = function(channel) {
641     if (!cr.isChromeOS)
642       return;
643     HelpPage.getInstance().updateCurrentChannel_(channel);
644   };
646   HelpPage.updateTargetChannel = function(channel) {
647     if (!cr.isChromeOS)
648       return;
649     HelpPage.getInstance().updateTargetChannel_(channel);
650   };
652   HelpPage.updateEnableReleaseChannel = function(enabled) {
653     HelpPage.getInstance().updateEnableReleaseChannel_(enabled);
654   };
656   HelpPage.setChannel = function(channel, isPowerwashAllowed) {
657     HelpPage.getInstance().setChannel_(channel, isPowerwashAllowed);
658   };
660   HelpPage.setBuildDate = function(buildDate) {
661     HelpPage.getInstance().setBuildDate_(buildDate);
662   };
664   HelpPage.setRegulatoryLabelPath = function(path) {
665     assert(cr.isChromeOS);
666     HelpPage.getInstance().setRegulatoryLabelPath_(path);
667   };
669   HelpPage.setRegulatoryLabelText = function(text) {
670     assert(cr.isChromeOS);
671     HelpPage.getInstance().setRegulatoryLabelText_(text);
672   };
674   // Export
675   return {
676     HelpPage: HelpPage
677   };