| Index: chrome/browser/resources/file_manager/js/directory_model.js
|
| diff --git a/chrome/browser/resources/file_manager/js/directory_model.js b/chrome/browser/resources/file_manager/js/directory_model.js
|
| index 0cc59331dc9f9b8719b390d0b09362e8b5c02c60..9471941dff8cc9df05537fd06755a272a878a198 100644
|
| --- a/chrome/browser/resources/file_manager/js/directory_model.js
|
| +++ b/chrome/browser/resources/file_manager/js/directory_model.js
|
| @@ -57,6 +57,21 @@ function DirectoryModel(root, singleSelection, showGData, metadataCache) {
|
| * @type {Object.<string, boolean>}
|
| */
|
| this.volumeReadOnlyStatus_ = {};
|
| +
|
| + /**
|
| + * Directory in which search results are displayed. Not null iff search
|
| + * results are being displayed.
|
| + * @private
|
| + * @type {Entry}
|
| + */
|
| + this.searchDirEntry_ = null;
|
| +
|
| + /**
|
| + * Is search in progress.
|
| + * @private
|
| + * @type {boolean}
|
| + */
|
| + this.isSearching_ = false;
|
| }
|
|
|
| /**
|
| @@ -93,6 +108,21 @@ DirectoryModel.DOWNLOADS_DIRECTORY = 'Downloads';
|
| DirectoryModel.GDATA_DIRECTORY = 'gdata';
|
|
|
| /**
|
| + * Root path used for displaying gdata content search results.
|
| + * Search results will be shown in directory 'GDATA_SEARCH_ROOT_PATH/query'.
|
| + *
|
| + * @const
|
| + * @type {string}
|
| + */
|
| +DirectoryModel.GDATA_SEARCH_ROOT_PATH = '/gdata/.search';
|
| +
|
| +/**
|
| + * @const
|
| + * @type {Array.<string>}
|
| + */
|
| +DirectoryModel.GDATA_SEARCH_ROOT_COMPONENTS = ['', 'gdata', '.search'];
|
| +
|
| +/**
|
| * DirectoryModel extends cr.EventTarget.
|
| */
|
| DirectoryModel.prototype.__proto__ = cr.EventTarget.prototype;
|
| @@ -150,6 +180,13 @@ DirectoryModel.prototype.isReadOnly = function() {
|
| };
|
|
|
| /**
|
| + * @return {boolean} True if search is in progress.
|
| + */
|
| +DirectoryModel.prototype.isSearching = function() {
|
| + return this.isSearching_;
|
| +};
|
| +
|
| +/**
|
| * @param {strin} path Path to check.
|
| * @return {boolean} True if the |path| is read only.
|
| */
|
| @@ -205,6 +242,16 @@ DirectoryModel.prototype.getCurrentDirEntry = function() {
|
| };
|
|
|
| /**
|
| + * If search results are being displayed, returns search directory, else returns
|
| + * current directory.
|
| + *
|
| + * @return {DirectoryEntry} search or directory entry.
|
| + */
|
| +DirectoryModel.prototype.getSearchOrCurrentDirEntry = function() {
|
| + return this.searchDirEntry_ || this.currentDirEntry_;
|
| +};
|
| +
|
| +/**
|
| * @return {string} Path for the current directory.
|
| */
|
| DirectoryModel.prototype.getCurrentDirPath = function() {
|
| @@ -409,7 +456,7 @@ DirectoryModel.prototype.createScanner_ = function(list, successCallback) {
|
| }
|
|
|
| return new DirectoryModel.Scanner(
|
| - this.currentDirEntry_,
|
| + this.getSearchOrCurrentDirEntry(),
|
| list,
|
| onSuccess,
|
| onFailure,
|
| @@ -497,6 +544,38 @@ DirectoryModel.prototype.prefetchCacheForSorting_ = function(entries,
|
| };
|
|
|
| /**
|
| + * Gets name that should be displayed in the UI for the entry.
|
| + * @param {string} path Full path of the entry whose display name we are
|
| + * getting.
|
| + * @param {string} defaultName Default name to use if no name is calculated.
|
| + * @return {string} Name to be used for display.
|
| + */
|
| +DirectoryModel.prototype.getDisplayName = function(path, defaultName) {
|
| + var searchResultName = util.getFileAndDisplayNameForGDataSearchResult(path);
|
| + return searchResultName ? searchResultName.displayName : defaultName;
|
| +};
|
| +
|
| +/**
|
| + * Creates file name that should be used as a new file name in filesystem
|
| + * operations while renaming. It the given entry is not a gdata search result
|
| + * entry, |newName| will be used.
|
| + *
|
| + * @private
|
| + * @param {Entry} entry Entry which is being renamed.
|
| + * @param {string} displayName The new file name provided by user.
|
| + * @return {string} File name that should be used in renaming filesystem
|
| + * operations.
|
| + */
|
| +DirectoryModel.prototype.getEntryName_ = function(entry, displayName) {
|
| + // If we are renaming gdata search result, we'll have to format newName to
|
| + // use in file system operation like: <resource_id>.<file_name>.
|
| + var searchResultName =
|
| + util.getFileAndDisplayNameForGDataSearchResult(entry.fullPath);
|
| + return searchResultName ? searchResultName.resourceId + '.' + displayName :
|
| + displayName;
|
| +};
|
| +
|
| +/**
|
| * Delete the list of files and directories from filesystem and
|
| * update the file list.
|
| * @param {Array.<Entry>} entries Entries to delete.
|
| @@ -533,11 +612,16 @@ DirectoryModel.prototype.deleteEntries = function(entries, opt_callback) {
|
| * @param {string} name Filename.
|
| */
|
| DirectoryModel.prototype.onEntryChanged = function(name) {
|
| - var currentEntry = this.currentDirEntry_;
|
| + var currentEntry = this.getSearchOrCurrentDirEntry();
|
| + if (currentEntry != this.currentDirEntry_)
|
| + return;
|
| var dm = this.fileList_;
|
| var self = this;
|
|
|
| function onEntryFound(entry) {
|
| + // Do nothing if current directory changed during async operations.
|
| + if (self.currentDirEntry_ != currentEntry)
|
| + return;
|
| self.prefetchCacheForSorting_([entry], function() {
|
| // Do nothing if current directory changed during async operations.
|
| if (self.currentDirEntry_ != currentEntry)
|
| @@ -565,7 +649,7 @@ DirectoryModel.prototype.onEntryChanged = function(name) {
|
| dm.splice(index, 1);
|
| };
|
|
|
| - util.resolvePath(this.currentDirEntry_, name, onEntryFound, onError);
|
| + util.resolvePath(currentEntry, name, onEntryFound, onError);
|
| };
|
|
|
| /**
|
| @@ -584,11 +668,12 @@ DirectoryModel.prototype.findIndexByName_ = function(name) {
|
| /**
|
| * Rename the entry in the filesystem and update the file list.
|
| * @param {Entry} entry Entry to rename.
|
| - * @param {string} newName New name.
|
| + * @param {string} newDisplayName New name.
|
| * @param {function} errorCallback Called on error.
|
| * @param {function} opt_successCallback Called on success.
|
| */
|
| -DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback,
|
| +DirectoryModel.prototype.renameEntry = function(entry, newDisplayName,
|
| + errorCallback,
|
| opt_successCallback) {
|
| var self = this;
|
| function onSuccess(newEntry) {
|
| @@ -597,25 +682,31 @@ DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback,
|
| var index = fileList.indexOf(entry);
|
| if (index >= 0)
|
| fileList.splice(index, 1, newEntry);
|
| - self.selectEntry(newName);
|
| + self.selectEntry(newEntry.name);
|
| // If the entry doesn't exist in the list it mean that it updated from
|
| // outside (probably by directory rescan).
|
| if (opt_successCallback)
|
| opt_successCallback();
|
| });
|
| }
|
| - entry.moveTo(this.currentDirEntry_, newName, onSuccess, errorCallback);
|
| +
|
| + var newEntryName = this.getEntryName_(entry, newDisplayName);
|
| + entry.moveTo(this.getSearchOrCurrentDirEntry(), newEntryName, onSuccess,
|
| + errorCallback);
|
| };
|
|
|
| /**
|
| * Checks if current directory contains a file or directory with this name.
|
| - * @param {string} newName Name to check.
|
| + * @param {string} entry Entry to which newName will be given.
|
| + * @param {string} displayName Name to check.
|
| * @param {function(boolean, boolean?)} callback Called when the result's
|
| * available. First parameter is true if the entry exists and second
|
| * is true if it's a file.
|
| */
|
| -DirectoryModel.prototype.doesExist = function(newName, callback) {
|
| - util.resolvePath(this.currentDirEntry_, newName,
|
| +DirectoryModel.prototype.doesExist = function(entry, displayName, callback) {
|
| + var entryName = this.getEntryName_(entry, displayName);
|
| +
|
| + util.resolvePath(this.getSearchOrCurrentDirEntry(), entryName,
|
| function(entry) {
|
| callback(true, entry.isFile);
|
| },
|
| @@ -661,7 +752,15 @@ DirectoryModel.prototype.createDirectory = function(name, successCallback,
|
| * @param {string} path New current directory path.
|
| */
|
| DirectoryModel.prototype.changeDirectory = function(path) {
|
| - this.resolveDirectory(path, function(directoryEntry) {
|
| + var targetPath = path;
|
| + // We should not be changing directory to gdata search path. If we do, default
|
| + // to gdata root.
|
| + if (DirectoryModel.isGDataSearchPath(path)) {
|
| + console.error('Attempt to change directory to search path.');
|
| + targetPath = '/' + DirectoryModel.GDATA_DIRECTORY;
|
| + }
|
| +
|
| + this.resolveDirectory(targetPath, function(directoryEntry) {
|
| this.changeDirectoryEntry_(false, directoryEntry);
|
| }.bind(this), function(error) {
|
| console.error('Error changing directory to ' + path + ': ', error);
|
| @@ -731,6 +830,7 @@ DirectoryModel.prototype.changeDirectoryOrRoot = function(path) {
|
| */
|
| DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry,
|
| opt_callback) {
|
| + this.clearSearch_();
|
| var previous = this.currentDirEntry_;
|
| this.currentDirEntry_ = dirEntry;
|
| function onRescanComplete() {
|
| @@ -1109,6 +1209,55 @@ DirectoryModel.prototype.prepareUnmount = function(rootPath) {
|
| };
|
|
|
| /**
|
| + * Performs search and displays results. The search type is dependent on the
|
| + * current directory. If we are currently on gdata, server side content search
|
| + * over gdata mount point. If the current directory is not on the gdata, file
|
| + * name search over current directory wil be performed.
|
| + *
|
| + * @param {string} query Query that will be searched for.
|
| + */
|
| +DirectoryModel.prototype.search = function(query) {
|
| + if (!query) {
|
| + this.clearSearch_();
|
| + return;
|
| + }
|
| +
|
| + this.isSearching_ = true;
|
| +
|
| + // If we are offline, let's fallback to file name search inside dir.
|
| + if (this.getRootType() == DirectoryModel.RootType.GDATA &&
|
| + !util.isOffline()) {
|
| + var self = this;
|
| + // Create shadow directory which will contein search results.
|
| + this.root_.getDirectory(DirectoryModel.createGDataSearchPath(query),
|
| + {create: false},
|
| + function(dir) {
|
| + self.searchDirEntry_ = dir;
|
| + self.rescanSoon();
|
| + });
|
| + } else {
|
| + this.searchDirEntry_ = this.currentDirEntry_;
|
| + this.addFilter(
|
| + 'searchbox',
|
| + function(e) {
|
| + return e.name.substring(0, query.length) == query;
|
| + });
|
| + }
|
| +};
|
| +
|
| +
|
| +/**
|
| + * Clears any state set by previous searches.
|
| + * @private
|
| + */
|
| +DirectoryModel.prototype.clearSearch_ = function() {
|
| + this.searchDirEntry_ = null;
|
| + this.isSearching_ = false;
|
| + // This will trigger rescan.
|
| + this.removeFilter('searchbox');
|
| +};
|
| +
|
| +/**
|
| * @param {string} path Any path.
|
| * @return {string} The root path.
|
| */
|
| @@ -1173,6 +1322,28 @@ DirectoryModel.isRootPath = function(path) {
|
| };
|
|
|
| /**
|
| + * Checks if the provided path is under gdata search.
|
| + *
|
| + * @param {string} path Path to be tested.
|
| + * @return {boolean} Is the path gdata search path.
|
| + */
|
| +DirectoryModel.isGDataSearchPath = function(path) {
|
| + return path == DirectoryModel.GDATA_SEARCH_ROOT_PATH ||
|
| + path.search(DirectoryModel.GDATA_SEARCH_ROOT_PATH + '/') == 0;
|
| +};
|
| +
|
| +/**
|
| + * Creates directory path in which gdata content search results for |query|
|
| + * should be displayed.
|
| + *
|
| + * @param {string} query Search query.
|
| + * @return {string} Virtual directory path for search results.
|
| + */
|
| +DirectoryModel.createGDataSearchPath = function(query) {
|
| + return DirectoryModel.GDATA_SEARCH_ROOT_PATH + '/' + query;
|
| +};
|
| +
|
| +/**
|
| * @constructor
|
| * @extends cr.EventTarget
|
| * @param {DirectoryEntry} dir Directory to scan.
|
|
|