Home | History | Annotate | Download | only in js
      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 'use strict';
      6 
      7 /**
      8  * Responsible for showing following banners in the file list.
      9  *  - WelcomeBanner
     10  *  - AuthFailBanner
     11  * @param {DirectoryModel} directoryModel The model.
     12  * @param {VolumeManager} volumeManager The manager.
     13  * @param {DOMDocument} document HTML document.
     14  * @param {boolean} showOffers True if we should show offer banners.
     15  * @constructor
     16  */
     17 function FileListBannerController(
     18     directoryModel, volumeManager, document, showOffers) {
     19   this.directoryModel_ = directoryModel;
     20   this.volumeManager_ = volumeManager;
     21   this.document_ = document;
     22   this.showOffers_ = showOffers;
     23   this.driveEnabled_ = false;
     24 
     25   this.initializeWelcomeBanner_();
     26   this.privateOnDirectoryChangedBound_ =
     27       this.privateOnDirectoryChanged_.bind(this);
     28 
     29   var handler = this.checkSpaceAndMaybeShowWelcomeBanner_.bind(this);
     30   this.directoryModel_.addEventListener('scan-completed', handler);
     31   this.directoryModel_.addEventListener('rescan-completed', handler);
     32   this.directoryModel_.addEventListener('directory-changed',
     33       this.onDirectoryChanged_.bind(this));
     34 
     35   this.unmountedPanel_ = this.document_.querySelector('#unmounted-panel');
     36   this.volumeManager_.addEventListener('drive-status-changed',
     37         this.updateDriveUnmountedPanel_.bind(this));
     38   this.volumeManager_.addEventListener('drive-connection-changed',
     39         this.onDriveConnectionChanged_.bind(this));
     40 
     41   chrome.storage.onChanged.addListener(this.onStorageChange_.bind(this));
     42   this.welcomeHeaderCounter_ = WELCOME_HEADER_COUNTER_LIMIT;
     43   this.warningDismissedCounter_ = 0;
     44   chrome.storage.local.get([WELCOME_HEADER_COUNTER_KEY, WARNING_DISMISSED_KEY],
     45                          function(values) {
     46     this.welcomeHeaderCounter_ =
     47         parseInt(values[WELCOME_HEADER_COUNTER_KEY]) || 0;
     48     this.warningDismissedCounter_ =
     49         parseInt(values[WARNING_DISMISSED_KEY]) || 0;
     50   }.bind(this));
     51 
     52   this.authFailedBanner_ =
     53       this.document_.querySelector('#drive-auth-failed-warning');
     54   var authFailedText = this.authFailedBanner_.querySelector('.drive-text');
     55   authFailedText.innerHTML = util.htmlUnescape(str('DRIVE_NOT_REACHED'));
     56   authFailedText.querySelector('a').addEventListener('click', function(e) {
     57     chrome.fileBrowserPrivate.logoutUser();
     58     e.preventDefault();
     59   });
     60   this.maybeShowAuthFailBanner_();
     61 }
     62 
     63 /**
     64  * FileListBannerController extends cr.EventTarget.
     65  */
     66 FileListBannerController.prototype.__proto__ = cr.EventTarget.prototype;
     67 
     68 /**
     69  * Key in localStorage to keep numer of times the Drive Welcome
     70  * banner has shown.
     71  */
     72 var WELCOME_HEADER_COUNTER_KEY = 'driveWelcomeHeaderCounter';
     73 
     74 // If the warning was dismissed before, this key stores the quota value
     75 // (as of the moment of dismissal).
     76 // If the warning was never dismissed or was reset this key stores 0.
     77 var WARNING_DISMISSED_KEY = 'driveSpaceWarningDismissed';
     78 
     79 /**
     80  * Maximum times Drive Welcome banner could have shown.
     81  */
     82 var WELCOME_HEADER_COUNTER_LIMIT = 25;
     83 
     84 /**
     85  * Location of the FAQ about Google Drive.
     86  */
     87 var GOOGLE_DRIVE_FAQ_URL =
     88       'https://support.google.com/chromeos/?p=filemanager_drive';
     89 
     90 /**
     91  * Location of the page to buy more storage for Google Drive.
     92  */
     93 var GOOGLE_DRIVE_BUY_STORAGE =
     94     'https://www.google.com/settings/storage';
     95 
     96 var GOOGLE_DRIVE_REDEEM =
     97     'http://www.google.com/intl/en/chrome/devices/goodies.html';
     98 
     99 /**
    100  * Location of the FAQ about the downloads directory.
    101  */
    102 var DOWNLOADS_FAQ_URL =
    103     'http://support.google.com/chromeos/bin/answer.py?answer=1061547';
    104 
    105 /**
    106  * Location of the help page about connecting to Google Drive.
    107  */
    108 var GOOGLE_DRIVE_ERROR_HELP_URL =
    109     'https://support.google.com/chromeos/?p=filemanager_driveerror';
    110 
    111 /**
    112  * Initializes the banner to promote DRIVE.
    113  * This method must be called before any of showing banner functions, and
    114  * also before registering them as callbacks.
    115  * @private
    116  */
    117 FileListBannerController.prototype.initializeWelcomeBanner_ = function() {
    118   this.useNewWelcomeBanner_ = (!util.boardIs('x86-mario') &&
    119                                !util.boardIs('x86-zgb') &&
    120                                !util.boardIs('x86-alex'));
    121 };
    122 
    123 /**
    124  * @param {number} value How many times the Drive Welcome header banner
    125  * has shown.
    126  * @private
    127  */
    128 FileListBannerController.prototype.setWelcomeHeaderCounter_ = function(value) {
    129   var values = {};
    130   values[WELCOME_HEADER_COUNTER_KEY] = value;
    131   chrome.storage.local.set(values);
    132 };
    133 
    134 /**
    135  * @param {number} value How many times the low space warning has dismissed.
    136  * @private
    137  */
    138 FileListBannerController.prototype.setWarningDismissedCounter_ =
    139     function(value) {
    140   var values = {};
    141   values[WARNING_DISMISSED_KEY] = value;
    142   chrome.storage.local.set(values);
    143 };
    144 
    145 /**
    146  * chrome.storage.onChanged event handler.
    147  * @param {Object.<string, Object>} changes Changes values.
    148  * @param {string} areaName "local" or "sync".
    149  * @private
    150  */
    151 FileListBannerController.prototype.onStorageChange_ = function(changes,
    152                                                                areaName) {
    153   if (areaName == 'local' && WELCOME_HEADER_COUNTER_KEY in changes) {
    154     this.welcomeHeaderCounter_ = changes[WELCOME_HEADER_COUNTER_KEY].newValue;
    155   }
    156   if (areaName == 'local' && WARNING_DISMISSED_KEY in changes) {
    157     this.warningDismissedCounter_ = changes[WARNING_DISMISSED_KEY].newValue;
    158   }
    159 };
    160 
    161 /**
    162  * Invoked when the drive connection status is change in the volume manager.
    163  * @private
    164  */
    165 FileListBannerController.prototype.onDriveConnectionChanged_ = function() {
    166   this.maybeShowAuthFailBanner_();
    167 };
    168 
    169 /**
    170  * @param {string} type 'none'|'page'|'header'.
    171  * @param {string} messageId Reource ID of the message.
    172  * @private
    173  */
    174 FileListBannerController.prototype.prepareAndShowWelcomeBanner_ =
    175     function(type, messageId) {
    176   this.showWelcomeBanner_(type);
    177 
    178   var container = this.document_.querySelector('.drive-welcome.' + type);
    179   if (container.firstElementChild)
    180     return;  // Do not re-create.
    181 
    182   if (!this.document_.querySelector('link[drive-welcome-style]')) {
    183     var style = this.document_.createElement('link');
    184     style.rel = 'stylesheet';
    185     style.href = 'css/drive_welcome.css';
    186     style.setAttribute('drive-welcome-style', '');
    187     this.document_.head.appendChild(style);
    188   }
    189 
    190   var wrapper = util.createChild(container, 'drive-welcome-wrapper');
    191   util.createChild(wrapper, 'drive-welcome-icon');
    192 
    193   var close = util.createChild(wrapper, 'cr-dialog-close');
    194   close.addEventListener('click', this.closeWelcomeBanner_.bind(this));
    195 
    196   var message = util.createChild(wrapper, 'drive-welcome-message');
    197 
    198   var title = util.createChild(message, 'drive-welcome-title');
    199 
    200   var text = util.createChild(message, 'drive-welcome-text');
    201   text.innerHTML = str(messageId);
    202 
    203   var links = util.createChild(message, 'drive-welcome-links');
    204 
    205   var more;
    206   if (this.useNewWelcomeBanner_) {
    207     var welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE');
    208     if (util.boardIs('link'))
    209       welcomeTitle = str('DRIVE_WELCOME_TITLE_ALTERNATIVE_1TB');
    210     title.textContent = welcomeTitle;
    211     more = util.createChild(links,
    212         'drive-welcome-button drive-welcome-start', 'a');
    213     more.textContent = str('DRIVE_WELCOME_CHECK_ELIGIBILITY');
    214     more.href = GOOGLE_DRIVE_REDEEM;
    215   } else {
    216     title.textContent = str('DRIVE_WELCOME_TITLE');
    217     more = util.createChild(links, 'plain-link', 'a');
    218     more.textContent = str('DRIVE_LEARN_MORE');
    219     more.href = GOOGLE_DRIVE_FAQ_URL;
    220   }
    221   more.target = '_blank';
    222 
    223   var dismiss;
    224   if (this.useNewWelcomeBanner_)
    225     dismiss = util.createChild(links, 'drive-welcome-button');
    226   else
    227     dismiss = util.createChild(links, 'plain-link');
    228 
    229   dismiss.classList.add('drive-welcome-dismiss');
    230   dismiss.textContent = str('DRIVE_WELCOME_DISMISS');
    231   dismiss.addEventListener('click', this.closeWelcomeBanner_.bind(this));
    232 
    233   this.previousDirWasOnDrive_ = false;
    234 };
    235 
    236 /**
    237  * Show or hide the "Low Google Drive space" warning.
    238  * @param {boolean} show True if the box need to be shown.
    239  * @param {Object} sizeStats Size statistics. Should be defined when showing the
    240  *     warning.
    241  * @private
    242  */
    243 FileListBannerController.prototype.showLowDriveSpaceWarning_ =
    244       function(show, sizeStats) {
    245   var box = this.document_.querySelector('#volume-space-warning');
    246 
    247   // Avoid showing two banners.
    248   // TODO(kaznacheev): Unify the low space warning and the promo header.
    249   if (show)
    250     this.cleanupWelcomeBanner_();
    251 
    252   if (box.hidden == !show)
    253     return;
    254 
    255   if (this.warningDismissedCounter_) {
    256     if (this.warningDismissedCounter_ ==
    257             sizeStats.totalSizeKB && // Quota had not changed
    258         sizeStats.remainingSizeKB / sizeStats.totalSizeKB < 0.15) {
    259       // Since the last dismissal decision the quota has not changed AND
    260       // the user did not free up significant space. Obey the dismissal.
    261       show = false;
    262     } else {
    263       // Forget the dismissal. Warning will be shown again.
    264       this.setWarningDismissedCounter_(0);
    265     }
    266   }
    267 
    268   box.textContent = '';
    269   if (show) {
    270     var icon = this.document_.createElement('div');
    271     icon.className = 'drive-icon';
    272     box.appendChild(icon);
    273 
    274     var text = this.document_.createElement('div');
    275     text.className = 'drive-text';
    276     text.textContent = strf('DRIVE_SPACE_AVAILABLE_LONG',
    277         util.bytesToString(sizeStats.remainingSizeKB * 1024));
    278     box.appendChild(text);
    279 
    280     var link = this.document_.createElement('a');
    281     link.className = 'plain-link';
    282     link.textContent = str('DRIVE_BUY_MORE_SPACE_LINK');
    283     link.href = GOOGLE_DRIVE_BUY_STORAGE;
    284     link.target = '_blank';
    285     box.appendChild(link);
    286 
    287     var close = this.document_.createElement('div');
    288     close.className = 'cr-dialog-close';
    289     box.appendChild(close);
    290     close.addEventListener('click', function(total) {
    291       window.localStorage[WARNING_DISMISSED_KEY] = total;
    292       box.hidden = true;
    293       this.requestRelayout_(100);
    294     }.bind(this, sizeStats.totalSizeKB));
    295   }
    296 
    297   if (box.hidden != !show) {
    298     box.hidden = !show;
    299     this.requestRelayout_(100);
    300   }
    301 };
    302 /**
    303  * Closes the Drive Welcome banner.
    304  * @private
    305  */
    306 FileListBannerController.prototype.closeWelcomeBanner_ = function() {
    307   this.cleanupWelcomeBanner_();
    308   // Stop showing the welcome banner.
    309   this.setWelcomeHeaderCounter_(WELCOME_HEADER_COUNTER_LIMIT);
    310 };
    311 
    312 /**
    313  * Shows or hides the welcome banner for drive.
    314  * @private
    315  */
    316 FileListBannerController.prototype.checkSpaceAndMaybeShowWelcomeBanner_ =
    317     function() {
    318   if (!this.isOnDrive()) {
    319     // We are not on the drive file system. Do not show (close) the welcome
    320     // banner.
    321     this.cleanupWelcomeBanner_();
    322     this.previousDirWasOnDrive_ = false;
    323     return;
    324   }
    325 
    326   if (this.welcomeHeaderCounter_ >= WELCOME_HEADER_COUNTER_LIMIT ||
    327       !this.directoryModel_.isDriveMounted()) {
    328     // The banner is already shown enough times or the drive FS is not mounted.
    329     // So, do nothing here.
    330     return;
    331   }
    332 
    333   if (!this.showOffers_) {
    334     // Because it is not necessary to show the offer, set
    335     // |useNewWelcomeBanner_| false here. Note that it probably should be able
    336     // to do this in the constructor, but there remains non-trivial path,
    337     // which may be causes |useNewWelcomeBanner_| == true's behavior even
    338     // if |showOffers_| is false.
    339     // TODO(hidehiko): Make sure if it is expected or not, and simplify
    340     // |showOffers_| if possible.
    341     this.useNewWelcomeBanner_ = false;
    342   }
    343 
    344   var self = this;
    345   if (self.useNewWelcomeBanner_) {
    346     // getSizeStats for Drive file system accesses to the server, so we should
    347     // minimize the invocation.
    348     chrome.fileBrowserPrivate.getSizeStats(
    349         util.makeFilesystemUrl(self.directoryModel_.getCurrentRootPath()),
    350         function(result) {
    351           var offerSpaceKb = util.boardIs('link') ?
    352               1024 * 1024 * 1024 :  // 1TB.
    353               100 * 1024 * 1024;  // 100GB.
    354           if (result && result.totalSizeKB >= offerSpaceKb) {
    355             self.useNewWelcomeBanner_ = false;
    356           }
    357           self.maybeShowWelcomeBanner_();
    358         });
    359   } else {
    360     self.maybeShowWelcomeBanner_();
    361   }
    362 };
    363 
    364 /**
    365  * Decides which banner should be shown, and show it. This method is designed
    366  * to be called only from checkSpaceAndMaybeShowWelcomeBanner_.
    367  * @private
    368  */
    369 FileListBannerController.prototype.maybeShowWelcomeBanner_ = function() {
    370   if (this.directoryModel_.getFileList().length == 0 &&
    371       this.welcomeHeaderCounter_ == 0) {
    372     // Only show the full page banner if the header banner was never shown.
    373     // Do not increment the counter.
    374     // The timeout below is required because sometimes another
    375     // 'rescan-completed' event arrives shortly with non-empty file list.
    376     setTimeout(function() {
    377       if (this.isOnDrive() && this.welcomeHeaderCounter_ == 0) {
    378         this.prepareAndShowWelcomeBanner_('page', 'DRIVE_WELCOME_TEXT_LONG');
    379       }
    380     }.bind(this), 2000);
    381   } else {
    382     // We do not want to increment the counter when the user navigates
    383     // between different directories on Drive, but we increment the counter
    384     // once anyway to prevent the full page banner from showing.
    385     if (!this.previousDirWasOnDrive_ || this.welcomeHeaderCounter_ == 0) {
    386       this.setWelcomeHeaderCounter_(this.welcomeHeaderCounter_ + 1);
    387       this.prepareAndShowWelcomeBanner_('header', 'DRIVE_WELCOME_TEXT_SHORT');
    388     }
    389   }
    390   this.previousDirWasOnDrive_ = true;
    391 };
    392 
    393 /**
    394  * @return {boolean} True if current directory is on Drive.
    395  */
    396 FileListBannerController.prototype.isOnDrive = function() {
    397   return this.directoryModel_.getCurrentRootType() === RootType.DRIVE;
    398 };
    399 
    400 /**
    401  * Shows the Drive Welcome banner.
    402  * @param {string} type 'page'|'head'|'none'.
    403  * @private
    404  */
    405 FileListBannerController.prototype.showWelcomeBanner_ = function(type) {
    406   var container = this.document_.querySelector('.dialog-container');
    407   if (container.getAttribute('drive-welcome') != type) {
    408     container.setAttribute('drive-welcome', type);
    409     this.requestRelayout_(200);  // Resize only after the animation is done.
    410   }
    411 };
    412 
    413 /**
    414  * Update the UI when the current directory changes.
    415  *
    416  * @param {cr.Event} event The directory-changed event.
    417  * @private
    418  */
    419 FileListBannerController.prototype.onDirectoryChanged_ = function(event) {
    420   var root = PathUtil.getTopDirectory(event.newDirEntry.fullPath);
    421   // Show (or hide) the low space warning.
    422   this.maybeShowLowSpaceWarning_(root);
    423 
    424   // Add or remove listener to show low space warning, if necessary.
    425   var isLowSpaceWarningTarget = this.isLowSpaceWarningTarget_(root);
    426   var previousRoot = PathUtil.getTopDirectory(event.previousDirEntry.fullPath);
    427   if (isLowSpaceWarningTarget !== this.isLowSpaceWarningTarget_(previousRoot)) {
    428     if (isLowSpaceWarningTarget) {
    429       chrome.fileBrowserPrivate.onDirectoryChanged.addListener(
    430           this.privateOnDirectoryChangedBound_);
    431     } else {
    432       chrome.fileBrowserPrivate.onDirectoryChanged.removeListener(
    433           this.privateOnDirectoryChangedBound_);
    434     }
    435   }
    436 
    437   if (!this.isOnDrive()) {
    438     this.cleanupWelcomeBanner_();
    439     this.authFailedBanner_.hidden = true;
    440   }
    441 
    442   this.updateDriveUnmountedPanel_();
    443   if (this.isOnDrive()) {
    444     this.unmountedPanel_.classList.remove('retry-enabled');
    445     this.maybeShowAuthFailBanner_();
    446   }
    447 };
    448 
    449 /**
    450  * @param {string} root Root directory to be checked.
    451  * @return {boolean} true if the file system specified by |root| is a target
    452  *     to show low space warning. Otherwise false.
    453  * @private
    454  */
    455 FileListBannerController.prototype.isLowSpaceWarningTarget_ = function(root) {
    456   return (root == RootDirectory.DOWNLOADS || root == RootDirectory.DRIVE);
    457 };
    458 
    459 /**
    460  * Callback which is invoked when the file system has been changed.
    461  * @param {Object} event chrome.fileBrowserPrivate.onDirectoryChanged event.
    462  * @private
    463  */
    464 FileListBannerController.prototype.privateOnDirectoryChanged_ = function(
    465     event) {
    466   var currentRoot = PathUtil.getTopDirectory(
    467       this.directoryModel_.getCurrentDirPath());
    468   var eventRoot = PathUtil.getTopDirectory(
    469       util.extractFilePath(event.directoryUrl));
    470   if (currentRoot == eventRoot) {
    471     // The file system we are currently on is changed.
    472     // So, check the free space.
    473     this.maybeShowLowSpaceWarning_(eventRoot);
    474   }
    475 };
    476 
    477 /**
    478  * Shows or hides the low space warning.
    479  * @param {string} root Root directory of the file system, which we are
    480  *     interested in.
    481  * @private
    482  */
    483 FileListBannerController.prototype.maybeShowLowSpaceWarning_ = function(root) {
    484   // TODO(kaznacheev): Unify the two low space warning.
    485   var threshold = 0;
    486   if (root === RootDirectory.DOWNLOADS) {
    487     this.showLowDriveSpaceWarning_(false);
    488     threshold = 0.2;
    489   } else if (root === RootDirectory.DRIVE) {
    490     this.showLowDownloadsSpaceWarning_(false);
    491     threshold = 0.1;
    492   } else {
    493     // If the current file system is neither the DOWNLOAD nor the DRIVE,
    494     // just hide the warning.
    495     this.showLowDownloadsSpaceWarning_(false);
    496     this.showLowDriveSpaceWarning_(false);
    497     return;
    498   }
    499 
    500   var self = this;
    501   chrome.fileBrowserPrivate.getSizeStats(
    502       util.makeFilesystemUrl(root),
    503       function(sizeStats) {
    504         var currentRoot = PathUtil.getTopDirectory(
    505             self.directoryModel_.getCurrentDirPath());
    506         if (root != currentRoot) {
    507           // This happens when the current directory is moved during requesting
    508           // the file system size. Just ignore it.
    509           return;
    510         }
    511 
    512         // sizeStats is undefined, if some error occurs.
    513         var remainingRatio = (sizeStats && sizeStats.totalSizeKB > 0) ?
    514             (sizeStats.remainingSizeKB / sizeStats.totalSizeKB) : 1;
    515         var isLowDiskSpace = remainingRatio < threshold;
    516         if (root == RootDirectory.DOWNLOADS)
    517           self.showLowDownloadsSpaceWarning_(isLowDiskSpace);
    518         else
    519           self.showLowDriveSpaceWarning_(isLowDiskSpace, sizeStats);
    520       });
    521 };
    522 
    523 /**
    524  * removes the Drive Welcome banner.
    525  * @private
    526  */
    527 FileListBannerController.prototype.cleanupWelcomeBanner_ = function() {
    528   this.showWelcomeBanner_('none');
    529 };
    530 
    531 /**
    532  * Notifies the file manager what layout must be recalculated.
    533  * @param {number} delay In milliseconds.
    534  * @private
    535  */
    536 FileListBannerController.prototype.requestRelayout_ = function(delay) {
    537   var self = this;
    538   setTimeout(function() {
    539     cr.dispatchSimpleEvent(self, 'relayout');
    540   }, delay);
    541 };
    542 
    543 /**
    544  * Show or hide the "Low disk space" warning.
    545  * @param {boolean} show True if the box need to be shown.
    546  * @private
    547  */
    548 FileListBannerController.prototype.showLowDownloadsSpaceWarning_ =
    549     function(show) {
    550   var box = this.document_.querySelector('.downloads-warning');
    551 
    552   if (box.hidden == !show) return;
    553 
    554   if (show) {
    555     var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING'));
    556     box.innerHTML = html;
    557     var link = box.querySelector('a');
    558     link.href = DOWNLOADS_FAQ_URL;
    559     link.target = '_blank';
    560   } else {
    561     box.innerHTML = '';
    562   }
    563 
    564   box.hidden = !show;
    565   this.requestRelayout_(100);
    566 };
    567 
    568 /**
    569  * Creates contents for the DRIVE unmounted panel.
    570  * @private
    571  */
    572 FileListBannerController.prototype.ensureDriveUnmountedPanelInitialized_ =
    573     function() {
    574   var panel = this.unmountedPanel_;
    575   if (panel.firstElementChild)
    576     return;
    577 
    578   var create = function(parent, tag, className, opt_textContent) {
    579     var div = panel.ownerDocument.createElement(tag);
    580     div.className = className;
    581     div.textContent = opt_textContent || '';
    582     parent.appendChild(div);
    583     return div;
    584   };
    585 
    586   var loading = create(panel, 'div', 'loading', str('DRIVE_LOADING'));
    587   var spinnerBox = create(loading, 'div', 'spinner-box');
    588   create(spinnerBox, 'div', 'spinner');
    589   create(panel, 'div', 'error', str('DRIVE_CANNOT_REACH'));
    590 
    591   var retryButton = create(panel, 'button', 'retry', str('DRIVE_RETRY'));
    592   retryButton.hidden = true;
    593   var vm = this.volumeManager_;
    594   retryButton.onclick = function() {
    595     vm.mountDrive(function() {}, function() {});
    596   };
    597 
    598   var learnMore = create(panel, 'a', 'learn-more plain-link',
    599                          str('DRIVE_LEARN_MORE'));
    600   learnMore.href = GOOGLE_DRIVE_ERROR_HELP_URL;
    601   learnMore.target = '_blank';
    602 };
    603 
    604 /**
    605  * Shows the panel when current directory is DRIVE and it's unmounted.
    606  * Hides it otherwise. The pannel shows spinner if DRIVE is mounting or
    607  * an error message if it failed.
    608  * @private
    609  */
    610 FileListBannerController.prototype.updateDriveUnmountedPanel_ = function() {
    611   var node = this.document_.body;
    612   if (this.isOnDrive()) {
    613     var status = this.volumeManager_.getDriveStatus();
    614     if (status == VolumeManager.DriveStatus.MOUNTING ||
    615         status == VolumeManager.DriveStatus.ERROR) {
    616       this.ensureDriveUnmountedPanelInitialized_();
    617     }
    618     if (status == VolumeManager.DriveStatus.MOUNTING &&
    619         this.welcomeHeaderCounter_ == 0) {
    620       // Do not increment banner counter in order to not prevent the full
    621       // page banner of being shown (otherwise it would never be shown).
    622       this.showWelcomeBanner_('header', 'DRIVE_WELCOME_TEXT_SHORT');
    623     }
    624     if (status == VolumeManager.DriveStatus.ERROR)
    625       this.unmountedPanel_.classList.add('retry-enabled');
    626     else
    627       this.unmountedPanel_.classList.remove('retry-enabled');
    628     node.setAttribute('drive', status);
    629   } else {
    630     node.removeAttribute('drive');
    631   }
    632 };
    633 
    634 /**
    635  * Updates the visibility of Drive Connection Warning banner, retrieving the
    636  * current connection information.
    637  * @private
    638  */
    639 FileListBannerController.prototype.maybeShowAuthFailBanner_ = function() {
    640   var connection = this.volumeManager_.getDriveConnectionState();
    641   var reasons = connection.reasons;
    642   var showDriveNotReachedMessage =
    643       this.isOnDrive() &&
    644       connection.type == VolumeManager.DriveConnectionType.OFFLINE &&
    645       // Show the banner only when authentication fails. Don't show it when the
    646       // drive service is disabled.
    647       reasons.indexOf(VolumeManager.DriveConnectionReason.NOT_READY) != -1 &&
    648       reasons.indexOf(VolumeManager.DriveConnectionReason.NO_SERVICE) == -1;
    649   this.authFailedBanner_.hidden = !showDriveNotReachedMessage;
    650 };
    651