Home | History | Annotate | Download | only in help
      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