function NavigationListModel(
    volumeManager, shortcutListModel, recentModelItem, addNewServicesItem) {
  cr.EventTarget.call(this);

  /**
   * @private {!VolumeManagerWrapper}
   * @const
   */
  this.volumeManager_ = volumeManager;

  /**
   * @private {(!cr.ui.ArrayDataModel|!FolderShortcutsDataModel)}
   * @const
   */
  this.shortcutListModel_ = shortcutListModel;

  /**
   * @private {NavigationModelFakeItem}
   * @const
   */
  this.recentModelItem_ = recentModelItem;

  /**
   * Root folder for crostini Linux Files.
   * This field will be set asynchronously after calling
   * chrome.fileManagerPrivate.isCrostiniEnabled.
   * @private {NavigationModelFakeItem}
   */
  this.linuxFilesItem_ = null;

  /**
   * @private {NavigationModelMenuItem}
   * @const
   */
  this.addNewServicesItem_ = addNewServicesItem;

  /**
   * All root navigation items in display order.
   * @private {!Array<!NavigationModelItem>}
   */
  this.navigationItems_ = [];

  var volumeInfoToModelItem = function(volumeInfo) {
    return new NavigationModelVolumeItem(
        volumeInfo.label,
        volumeInfo);
  }.bind(this);

  var entryToModelItem = function(entry) {
    var item = new NavigationModelShortcutItem(
        entry.name,
        entry);
    return item;
  }.bind(this);

  /**
   * Type of updated list.
   * @enum {number}
   * @const
   */
  var ListType = {
    VOLUME_LIST: 1,
    SHORTCUT_LIST: 2
  };
  Object.freeze(ListType);

  // Generates this.volumeList_ and this.shortcutList_ from the models.
  this.volumeList_ =
      this.volumeManager_.volumeInfoList.slice().map(volumeInfoToModelItem);

  this.shortcutList_ = [];
  for (var i = 0; i < this.shortcutListModel_.length; i++) {
    var shortcutEntry = /** @type {!Entry} */ (this.shortcutListModel_.item(i));
    var volumeInfo = this.volumeManager_.getVolumeInfo(shortcutEntry);
    this.shortcutList_.push(entryToModelItem(shortcutEntry));
  }

  // Reorder volumes, shortcuts, and optional items for initial display.
  this.reorderNavigationItems_();

  // Generates a combined 'permuted' event from an event of either volumeList or
  // shortcutList.
  var permutedHandler = function(listType, event) {
    var permutation;

    // Build the volumeList.
    if (listType == ListType.VOLUME_LIST) {
      // The volume is mounted or unmounted.
      var newList = [];

      // Use the old instances if they just move.
      for (var i = 0; i < event.permutation.length; i++) {
        if (event.permutation[i] >= 0)
          newList[event.permutation[i]] = this.volumeList_[i];
      }

      // Create missing instances.
      for (var i = 0; i < event.newLength; i++) {
        if (!newList[i]) {
          newList[i] = volumeInfoToModelItem(
              this.volumeManager_.volumeInfoList.item(i));
        }
      }
      this.volumeList_ = newList;

      permutation = event.permutation.slice();

      // shortcutList part has not been changed, so the permutation should be
      // just identity mapping with a shift.
      for (var i = 0; i < this.shortcutList_.length; i++) {
        permutation.push(i + this.volumeList_.length);
      }
    } else {
      // Build the shortcutList.

      // volumeList part has not been changed, so the permutation should be
      // identity mapping.

      permutation = [];
      for (var i = 0; i < this.volumeList_.length; i++) {
        permutation[i] = i;
      }

      var modelIndex = 0;
      var oldListIndex = 0;
      var newList = [];
      while (modelIndex < this.shortcutListModel_.length &&
             oldListIndex < this.shortcutList_.length) {
        var shortcutEntry = this.shortcutListModel_.item(modelIndex);
        var cmp = this.shortcutListModel_.compare(
            /** @type {Entry} */ (shortcutEntry),
            this.shortcutList_[oldListIndex].entry);
        if (cmp > 0) {
          // The shortcut at shortcutList_[oldListIndex] is removed.
          permutation.push(-1);
          oldListIndex++;
          continue;
        }

        if (cmp === 0) {
          // Reuse the old instance.
          permutation.push(newList.length + this.volumeList_.length);
          newList.push(this.shortcutList_[oldListIndex]);
          oldListIndex++;
        } else {
          // We needs to create a new instance for the shortcut entry.
          newList.push(entryToModelItem(shortcutEntry));
        }
        modelIndex++;
      }

      // Add remaining (new) shortcuts if necessary.
      for (; modelIndex < this.shortcutListModel_.length; modelIndex++) {
        var shortcutEntry = this.shortcutListModel_.item(modelIndex);
        newList.push(entryToModelItem(shortcutEntry));
      }

      // Fill remaining permutation if necessary.
      for (; oldListIndex < this.shortcutList_.length; oldListIndex++)
        permutation.push(-1);

      this.shortcutList_ = newList;
    }

    // Reorder items after permutation.
    this.reorderNavigationItems_();

    // Dispatch permuted event.
    var permutedEvent = new Event('permuted');
    permutedEvent.newLength =
        this.volumeList_.length + this.shortcutList_.length;
    permutedEvent.permutation = permutation;
    this.dispatchEvent(permutedEvent);
  };

  this.volumeManager_.volumeInfoList.addEventListener(
      'permuted', permutedHandler.bind(this, ListType.VOLUME_LIST));
  this.shortcutListModel_.addEventListener(
      'permuted', permutedHandler.bind(this, ListType.SHORTCUT_LIST));

  // 'change' event is just ignored, because it is not fired neither in
  // the folder shortcut list nor in the volume info list.
  // 'splice' and 'sorted' events are not implemented, since they are not used
  // in list.js.
}
/**
 * A navigation list model. This model combines multiple models.
 * @param {!VolumeManagerWrapper} volumeManager VolumeManagerWrapper instance.
 * @param {(!cr.ui.ArrayDataModel|!FolderShortcutsDataModel)} shortcutListModel
 *     The list of folder shortcut.
 * @param {NavigationModelFakeItem} recentModelItem Recent folder.
 * @param {NavigationModelMenuItem} addNewServicesItem Add new services item.
 * @constructor
 * @extends {cr.EventTarget}
 */
A navigation list model. This model combines multiple models.
A navigation list model . This model combines multiple models .
function NavigationListModel(
    volumeManager, shortcutListModel, recentModelItem, addNewServicesItem) {
  cr.EventTarget.call(this);
  this.volumeManager_ = volumeManager;
  this.shortcutListModel_ = shortcutListModel;
  this.recentModelItem_ = recentModelItem;
  this.linuxFilesItem_ = null;
  this.addNewServicesItem_ = addNewServicesItem;
  this.navigationItems_ = [];
  var volumeInfoToModelItem = function(volumeInfo) {
    return new NavigationModelVolumeItem(
        volumeInfo.label,
        volumeInfo);
  }.bind(this);
  var entryToModelItem = function(entry) {
    var item = new NavigationModelShortcutItem(
        entry.name,
        entry);
    return item;
  }.bind(this);
  var ListType = {
    VOLUME_LIST: 1,
    SHORTCUT_LIST: 2
  };
  Object.freeze(ListType);
  this.volumeList_ =
      this.volumeManager_.volumeInfoList.slice().map(volumeInfoToModelItem);
  this.shortcutList_ = [];
  for (var i = 0; i < this.shortcutListModel_.length; i++) {
    var shortcutEntry =  (this.shortcutListModel_.item(i));
    var volumeInfo = this.volumeManager_.getVolumeInfo(shortcutEntry);
    this.shortcutList_.push(entryToModelItem(shortcutEntry));
  }
  this.reorderNavigationItems_();
  var permutedHandler = function(listType, event) {
    var permutation;
    if (listType == ListType.VOLUME_LIST) {
      var newList = [];
      for (var i = 0; i < event.permutation.length; i++) {
        if (event.permutation[i] >= 0)
          newList[event.permutation[i]] = this.volumeList_[i];
      }
      for (var i = 0; i < event.newLength; i++) {
        if (!newList[i]) {
          newList[i] = volumeInfoToModelItem(
              this.volumeManager_.volumeInfoList.item(i));
        }
      }
      this.volumeList_ = newList;
      permutation = event.permutation.slice();
      for (var i = 0; i < this.shortcutList_.length; i++) {
        permutation.push(i + this.volumeList_.length);
      }
    } else {
      permutation = [];
      for (var i = 0; i < this.volumeList_.length; i++) {
        permutation[i] = i;
      }
      var modelIndex = 0;
      var oldListIndex = 0;
      var newList = [];
      while (modelIndex < this.shortcutListModel_.length &&
             oldListIndex < this.shortcutList_.length) {
        var shortcutEntry = this.shortcutListModel_.item(modelIndex);
        var cmp = this.shortcutListModel_.compare(
             (shortcutEntry),
            this.shortcutList_[oldListIndex].entry);
        if (cmp > 0) {
          permutation.push(-1);
          oldListIndex++;
          continue;
        }
        if (cmp === 0) {
          permutation.push(newList.length + this.volumeList_.length);
          newList.push(this.shortcutList_[oldListIndex]);
          oldListIndex++;
        } else {
          newList.push(entryToModelItem(shortcutEntry));
        }
        modelIndex++;
      }
      for (; modelIndex < this.shortcutListModel_.length; modelIndex++) {
        var shortcutEntry = this.shortcutListModel_.item(modelIndex);
        newList.push(entryToModelItem(shortcutEntry));
      }
      for (; oldListIndex < this.shortcutList_.length; oldListIndex++)
        permutation.push(-1);
      this.shortcutList_ = newList;
    }
    this.reorderNavigationItems_();
    var permutedEvent = new Event('permuted');
    permutedEvent.newLength =
        this.volumeList_.length + this.shortcutList_.length;
    permutedEvent.permutation = permutation;
    this.dispatchEvent(permutedEvent);
  };
  this.volumeManager_.volumeInfoList.addEventListener(
      'permuted', permutedHandler.bind(this, ListType.VOLUME_LIST));
  this.shortcutListModel_.addEventListener(
      'permuted', permutedHandler.bind(this, ListType.SHORTCUT_LIST));
}
function NavigationListModel ( volumeManager , shortcutListModel , recentModelItem , addNewServicesItem ) { cr . EventTarget . call ( this ) ; this . volumeManager_ = volumeManager ; this . shortcutListModel_ = shortcutListModel ; this . recentModelItem_ = recentModelItem ; this . linuxFilesItem_ = null ; this . addNewServicesItem_ = addNewServicesItem ; this . navigationItems_ = [ ] ; var volumeInfoToModelItem = function ( volumeInfo ) { return new NavigationModelVolumeItem ( volumeInfo . label , volumeInfo ) ; } . bind ( this ) ; var entryToModelItem = function ( entry ) { var item = new NavigationModelShortcutItem ( entry . name , entry ) ; return item ; } . bind ( this ) ; var ListType = { VOLUME_LIST : 1 , SHORTCUT_LIST : 2 } ; Object . freeze ( ListType ) ; this . volumeList_ = this . volumeManager_ . volumeInfoList . slice ( ) . map ( volumeInfoToModelItem ) ; this . shortcutList_ = [ ] ; for ( var i = 0 ; i < this . shortcutListModel_ . length ; i ++ ) { var shortcutEntry = ( this . shortcutListModel_ . item ( i ) ) ; var volumeInfo = this . volumeManager_ . getVolumeInfo ( shortcutEntry ) ; this . shortcutList_ . push ( entryToModelItem ( shortcutEntry ) ) ; } this . reorderNavigationItems_ ( ) ; var permutedHandler = function ( listType , event ) { var permutation ; if ( listType == ListType . VOLUME_LIST ) { var newList = [ ] ; for ( var i = 0 ; i < event . permutation . length ; i ++ ) { if ( event . permutation [ i ] >= 0 ) newList [ event . permutation [ i ] ] = this . volumeList_ [ i ] ; } for ( var i = 0 ; i < event . newLength ; i ++ ) { if ( ! newList [ i ] ) { newList [ i ] = volumeInfoToModelItem ( this . volumeManager_ . volumeInfoList . item ( i ) ) ; } } this . volumeList_ = newList ; permutation = event . permutation . slice ( ) ; for ( var i = 0 ; i < this . shortcutList_ . length ; i ++ ) { permutation . push ( i + this . volumeList_ . length ) ; } } else { permutation = [ ] ; for ( var i = 0 ; i < this . volumeList_ . length ; i ++ ) { permutation [ i ] = i ; } var modelIndex = 0 ; var oldListIndex = 0 ; var newList = [ ] ; while ( modelIndex < this . shortcutListModel_ . length && oldListIndex < this . shortcutList_ . length ) { var shortcutEntry = this . shortcutListModel_ . item ( modelIndex ) ; var cmp = this . shortcutListModel_ . compare ( ( shortcutEntry ) , this . shortcutList_ [ oldListIndex ] . entry ) ; if ( cmp > 0 ) { permutation . push ( - 1 ) ; oldListIndex ++ ; continue ; } if ( cmp === 0 ) { permutation . push ( newList . length + this . volumeList_ . length ) ; newList . push ( this . shortcutList_ [ oldListIndex ] ) ; oldListIndex ++ ; } else { newList . push ( entryToModelItem ( shortcutEntry ) ) ; } modelIndex ++ ; } for ( ; modelIndex < this . shortcutListModel_ . length ; modelIndex ++ ) { var shortcutEntry = this . shortcutListModel_ . item ( modelIndex ) ; newList . push ( entryToModelItem ( shortcutEntry ) ) ; } for ( ; oldListIndex < this . shortcutList_ . length ; oldListIndex ++ ) permutation . push ( - 1 ) ; this . shortcutList_ = newList ; } this . reorderNavigationItems_ ( ) ; var permutedEvent = new Event ( 'permuted' ) ; permutedEvent . newLength = this . volumeList_ . length + this . shortcutList_ . length ; permutedEvent . permutation = permutation ; this . dispatchEvent ( permutedEvent ) ; } ; this . volumeManager_ . volumeInfoList . addEventListener ( 'permuted' , permutedHandler . bind ( this , ListType . VOLUME_LIST ) ) ; this . shortcutListModel_ . addEventListener ( 'permuted' , permutedHandler . bind ( this , ListType . SHORTCUT_LIST ) ) ; }
A navigation list model.
A navigation list model .
/**
   * @private {!VolumeManagerWrapper}
   * @const
   */ /**
   * @private {(!cr.ui.ArrayDataModel|!FolderShortcutsDataModel)}
   * @const
   */ /**
   * @private {NavigationModelFakeItem}
   * @const
   */ /**
   * Root folder for crostini Linux Files.
   * This field will be set asynchronously after calling
   * chrome.fileManagerPrivate.isCrostiniEnabled.
   * @private {NavigationModelFakeItem}
   */ /**
   * @private {NavigationModelMenuItem}
   * @const
   */ /**
   * All root navigation items in display order.
   * @private {!Array<!NavigationModelItem>}
   */ /**
   * Type of updated list.
   * @enum {number}
   * @const
   */ // Generates this.volumeList_ and this.shortcutList_ from the models. /** @type {!Entry} */ // Reorder volumes, shortcuts, and optional items for initial display. // Generates a combined 'permuted' event from an event of either volumeList or // shortcutList. // Build the volumeList. // The volume is mounted or unmounted. // Use the old instances if they just move. // Create missing instances. // shortcutList part has not been changed, so the permutation should be // just identity mapping with a shift. // Build the shortcutList. // volumeList part has not been changed, so the permutation should be // identity mapping. /** @type {Entry} */ // The shortcut at shortcutList_[oldListIndex] is removed. // Reuse the old instance. // We needs to create a new instance for the shortcut entry. // Add remaining (new) shortcuts if necessary. // Fill remaining permutation if necessary. // Reorder items after permutation. // Dispatch permuted event. // 'change' event is just ignored, because it is not fired neither in // the folder shortcut list nor in the volume info list. // 'splice' and 'sorted' events are not implemented, since they are not used // in list.js.