blob: 02a49d9e0a5954efe34eef4f4c7ad333cf4c8833 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// clang-format off
// #import {FilesAppEntry, FakeEntry} from '../../../externs/files_app_entry_interfaces.m.js';
// #import {VolumeManagerCommon} from '../../../base/js/volume_manager_types.m.js';
// #import {util, str} from '../../common/js/util.m.js';
// clang-format on
/**
* File path component.
*
* File path can be represented as a series of path components. Each component
* has its name used as a visible label and URL which point to the component
* in the path.
* PathComponent.computeComponentsFromEntry computes an array of PathComponent
* of the given entry.
*/
/* #export */ class PathComponent {
/**
* @param {string} name Name.
* @param {string} url Url.
* @param {FilesAppEntry=} opt_fakeEntry Fake entry should be set when
* this component represents fake entry.
*/
constructor(name, url, opt_fakeEntry) {
this.name = name;
this.url_ = url;
this.fakeEntry_ = opt_fakeEntry || null;
}
/**
* Resolve an entry of the component.
* @return {!Promise<!Entry|!FilesAppEntry>} A promise which is
* resolved with an entry.
*/
resolveEntry() {
if (this.fakeEntry_) {
return /** @type {!Promise<!Entry|!FilesAppEntry>} */ (
Promise.resolve(this.fakeEntry_));
} else {
return new Promise(
window.webkitResolveLocalFileSystemURL.bind(null, this.url_));
}
}
/**
* Computes path components for the path of entry.
* @param {!Entry|!FilesAppEntry} entry An entry.
* @return {!Array<!PathComponent>} Components.
*/
static computeComponentsFromEntry(entry, volumeManager) {
/**
* Replace the root directory name at the end of a url.
* The input, |url| is a displayRoot URL of a Drive volume like
* filesystem:chrome-extension://....foo.com-hash/root
* The output is like:
* filesystem:chrome-extension://....foo.com-hash/other
*
* @param {string} url which points to a volume display root
* @param {string} newRoot new root directory name
* @return {string} new URL with the new root directory name
*/
const replaceRootName = (url, newRoot) => {
return url.slice(0, url.length - '/root'.length) + newRoot;
};
const components = [];
const locationInfo = volumeManager.getLocationInfo(entry);
if (!locationInfo) {
return components;
}
if (util.isFakeEntry(entry)) {
components.push(new PathComponent(
util.getEntryLabel(locationInfo, entry), entry.toURL(),
/** @type {!FakeEntry} */ (entry)));
return components;
}
// Add volume component.
let displayRootUrl = locationInfo.volumeInfo.displayRoot.toURL();
let displayRootFullPath = locationInfo.volumeInfo.displayRoot.fullPath;
const prefixEntry = locationInfo.volumeInfo.prefixEntry;
if (prefixEntry) {
components.push(new PathComponent(
prefixEntry.name, prefixEntry.toURL(), prefixEntry));
}
if (locationInfo.rootType === VolumeManagerCommon.RootType.DRIVE_OTHER) {
// When target path is a shared directory, volume should be shared with
// me.
const match = entry.fullPath.match(/\/\.files-by-id\/\d+\//);
if (match) {
displayRootFullPath = match[0];
} else {
displayRootFullPath = '/other';
}
displayRootUrl = replaceRootName(displayRootUrl, displayRootFullPath);
const sharedWithMeFakeEntry =
locationInfo.volumeInfo
.fakeEntries[VolumeManagerCommon.RootType.DRIVE_SHARED_WITH_ME];
components.push(new PathComponent(
str('DRIVE_SHARED_WITH_ME_COLLECTION_LABEL'),
sharedWithMeFakeEntry.toURL(), sharedWithMeFakeEntry));
} else if (
locationInfo.rootType === VolumeManagerCommon.RootType.SHARED_DRIVE) {
displayRootUrl = replaceRootName(
displayRootUrl, VolumeManagerCommon.SHARED_DRIVES_DIRECTORY_PATH);
components.push(new PathComponent(
util.getRootTypeLabel(locationInfo), displayRootUrl));
} else if (
locationInfo.rootType === VolumeManagerCommon.RootType.COMPUTER) {
displayRootUrl = replaceRootName(
displayRootUrl, VolumeManagerCommon.COMPUTERS_DIRECTORY_PATH);
components.push(new PathComponent(
util.getRootTypeLabel(locationInfo), displayRootUrl));
} else {
components.push(new PathComponent(
util.getRootTypeLabel(locationInfo), displayRootUrl));
}
// Get relative path to display root (e.g. /root/foo/bar -> foo/bar).
let relativePath = entry.fullPath.slice(displayRootFullPath.length);
if (entry.fullPath.startsWith(
VolumeManagerCommon.SHARED_DRIVES_DIRECTORY_PATH)) {
relativePath = entry.fullPath.slice(
VolumeManagerCommon.SHARED_DRIVES_DIRECTORY_PATH.length);
} else if (entry.fullPath.startsWith(
VolumeManagerCommon.COMPUTERS_DIRECTORY_PATH)) {
relativePath = entry.fullPath.slice(
VolumeManagerCommon.COMPUTERS_DIRECTORY_PATH.length);
}
if (relativePath.indexOf('/') === 0) {
relativePath = relativePath.slice(1);
}
if (relativePath.length === 0) {
return components;
}
// currentUrl should be without trailing slash.
let currentUrl = /^.+\/$/.test(displayRootUrl) ?
displayRootUrl.slice(0, displayRootUrl.length - 1) :
displayRootUrl;
// Add directory components to the target path.
const paths = relativePath.split('/');
for (let i = 0; i < paths.length; i++) {
currentUrl += '/' + encodeURIComponent(paths[i]);
let path = paths[i];
if (i === 0 &&
locationInfo.rootType === VolumeManagerCommon.RootType.DOWNLOADS) {
if (path === 'Downloads') {
path = str('DOWNLOADS_DIRECTORY_LABEL');
}
if (path === 'PvmDefault') {
path = str('PLUGIN_VM_DIRECTORY_LABEL');
}
if (util.isFilesCameraFolderEnabled() && path === 'Camera') {
path = str('CAMERA_DIRECTORY_LABEL');
}
}
components.push(new PathComponent(path, currentUrl));
}
return components;
}
}