diff options
author | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-19 02:41:07 +0000 |
---|---|---|
committer | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-19 02:41:07 +0000 |
commit | c5196354466d32b04527c4969df70d147035f4b0 (patch) | |
tree | 6bfc76490da93cc0209a81197b99d04a9f53b94c | |
parent | 6f5b411b3934ba31b1a4befbe9e654ecfa8e7e2d (diff) | |
download | chromium_src-c5196354466d32b04527c4969df70d147035f4b0.zip chromium_src-c5196354466d32b04527c4969df70d147035f4b0.tar.gz chromium_src-c5196354466d32b04527c4969df70d147035f4b0.tar.bz2 |
Add search directory scanner to directory model.
Following has to land before this:
https://chromiumcodereview.appspot.com/10548032/
https://chromiumcodereview.appspot.com/10537166/
BUG=129068
TEST=manual, with search through api in place
Review URL: https://chromiumcodereview.appspot.com/10539165
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@142903 0039d316-1c4b-4281-b951-d872f2087c98
4 files changed, 171 insertions, 364 deletions
diff --git a/chrome/browser/resources/file_manager/js/directory_model.js b/chrome/browser/resources/file_manager/js/directory_model.js index 9fcfd0e..4882623 100644 --- a/chrome/browser/resources/file_manager/js/directory_model.js +++ b/chrome/browser/resources/file_manager/js/directory_model.js @@ -57,14 +57,6 @@ function DirectoryModel(root, singleSelection, this.volumeManager_ = volumeManager; /** - * 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} @@ -115,21 +107,6 @@ DirectoryModel.fakeGDataEntry_ = { }; /** - * 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 = '/drive/.search'; - -/** - * @const - * @type {Array.<string>} - */ -DirectoryModel.GDATA_SEARCH_ROOT_COMPONENTS = ['', 'drive', '.search']; - -/** * DirectoryModel extends cr.EventTarget. */ DirectoryModel.prototype.__proto__ = cr.EventTarget.prototype; @@ -231,14 +208,7 @@ DirectoryModel.prototype.isSearching = function() { }; /** - * @return {boolean} True if we are currently showing search results. - */ -DirectoryModel.prototype.isOnGDataSearchDir = function() { - return this.getSearchOrCurrentDirEntry() != this.getCurrentDirEntry(); -}; - -/** - * @param {strin} path Path to check. + * @param {string} path Path to check. * @return {boolean} True if the |path| is read only. */ DirectoryModel.prototype.isPathReadOnly = function(path) { @@ -283,16 +253,6 @@ 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() { @@ -485,31 +445,57 @@ DirectoryModel.prototype.rescan = function() { */ DirectoryModel.prototype.createScanner_ = function(list, successCallback) { var self = this; - function onSuccess() { - self.scanFailures_ = 0; - successCallback(); + + /** + * Runs pending scan if there is one. + * + * @return {boolean} Did pending scan exist. + */ + function maybeRunPendingScan() { if (self.pendingScan_) { self.runningScan_ = self.pendingScan_; self.pendingScan_ = null; self.runningScan_.run(); - } else { - self.runningScan_ = null; + return true; } + self.runningScan_ = null; + return false; + } + + function onSuccess() { + successCallback(); + self.scanFailures_ = 0; + maybeRunPendingScan(); } function onFailure() { self.scanFailures_++; + + if (maybeRunPendingScan()) + return; + if (self.scanFailures_ <= 1) self.rescanLater(); } - return new DirectoryModel.Scanner( - this.getSearchOrCurrentDirEntry(), - list, - onSuccess, - onFailure, - this.prefetchCacheForSorting_.bind(this), - this.filters_); + if (!this.isSearching() || + this.getCurrentRootType() != DirectoryModel.RootType.GDATA) { + return new DirectoryModel.Scanner( + this.getCurrentDirEntry(), + list, + onSuccess, + onFailure, + this.prefetchCacheForSorting_.bind(this), + this.filters_); + } else { + return new DirectoryModel.GDataSearchScanner( + this.searchQuery_, + list, + onSuccess, + onFailure, + this.prefetchCacheForSorting_.bind(this), + this.filters_); + } }; /** @@ -554,6 +540,11 @@ DirectoryModel.prototype.scan_ = function(callback) { clearTimeout(this.rescanTimeout_); this.rescanTimeout_ = 0; } + + if (this.pendingScan_) { + this.pendingScan_ = null; + } + if (this.runningScan_) { this.runningScan_.cancel(); this.runningScan_ = null; @@ -587,38 +578,6 @@ 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. If the given entry is not a gdata search result - * entry, |displayName| 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.getEntryNameForRename_ = 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. @@ -655,19 +614,17 @@ DirectoryModel.prototype.deleteEntries = function(entries, opt_callback) { * @param {string} name Filename. */ DirectoryModel.prototype.onEntryChanged = function(name) { - var currentEntry = this.getSearchOrCurrentDirEntry(); - if (currentEntry != this.currentDirEntry_) - return; + var currentEntry = this.getCurrentDirEntry(); var dm = this.fileList_; var self = this; function onEntryFound(entry) { // Do nothing if current directory changed during async operations. - if (self.getSearchOrCurrentDirEntry() != currentEntry) + if (self.getCurrentDirEntry() != currentEntry) return; self.prefetchCacheForSorting_([entry], function() { // Do nothing if current directory changed during async operations. - if (self.getSearchOrCurrentDirEntry() != currentEntry) + if (self.getCurrentDirEntry() != currentEntry) return; var index = self.findIndexByName_(name); @@ -711,11 +668,11 @@ DirectoryModel.prototype.findIndexByName_ = function(name) { /** * Rename the entry in the filesystem and update the file list. * @param {Entry} entry Entry to rename. - * @param {string} newDisplayName New name. + * @param {string} newName New name. * @param {function} errorCallback Called on error. * @param {function} opt_successCallback Called on success. */ -DirectoryModel.prototype.renameEntry = function(entry, newDisplayName, +DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback, opt_successCallback) { var self = this; @@ -732,27 +689,31 @@ DirectoryModel.prototype.renameEntry = function(entry, newDisplayName, }); } - var newEntryName = this.getEntryNameForRename_(entry, newDisplayName); - entry.moveTo(this.getSearchOrCurrentDirEntry(), newEntryName, onSuccess, - errorCallback); + function onParentFound(parentEntry) { + entry.moveTo(parentEntry, newName, onSuccess, errorCallback); + } + + entry.getParent(onParentFound, errorCallback); }; /** * Checks if current directory contains a file or directory with this name. * @param {string} entry Entry to which newName will be given. - * @param {string} displayName Name to check. + * @param {string} name 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(entry, displayName, callback) { - var entryName = this.getEntryNameForRename_(entry, displayName); +DirectoryModel.prototype.doesExist = function(entry, name, callback) { + function onParentFound(parentEntry) { + util.resolvePath(parentEntry, name, + function(foundEntry) { + callback(true, foundEntry.isFile); + }, + callback.bind(window, false)); + } - util.resolvePath(this.getSearchOrCurrentDirEntry(), entryName, - function(entry) { - callback(true, entry.isFile); - }, - callback.bind(window, false)); + entry.getParent(onParentFound, callback.bind(window, false)); }; /** @@ -794,15 +755,7 @@ DirectoryModel.prototype.createDirectory = function(name, successCallback, * @param {string} path New current directory path. */ DirectoryModel.prototype.changeDirectory = function(path) { - 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.resolveDirectory(path, function(directoryEntry) { this.changeDirectoryEntry_(false, directoryEntry); }.bind(this), function(error) { console.error('Error changing directory to ' + path + ': ', error); @@ -1311,19 +1264,10 @@ DirectoryModel.prototype.search = function(query, if (this.getRootType() == DirectoryModel.RootType.GDATA && !this.isOffline()) { var self = this; - // Create shadow directory which will contain search results. - this.root_.getDirectory(DirectoryModel.createGDataSearchPath(query), - {create: false}, - function(dir) { - self.searchDirEntry_ = dir; - self.rescanSoon(); - }, - function() { - self.isSearching_ = false; - }); + this.searchQuery_ = query; + this.rescanSoon(); } else { var queryLC = query.toLowerCase(); - this.searchDirEntry_ = this.currentDirEntry_; this.addFilter( 'searchbox', function(e) { @@ -1340,7 +1284,7 @@ DirectoryModel.prototype.search = function(query, DirectoryModel.prototype.clearSearch_ = function() { if (!this.isSearching_) return; - this.searchDirEntry_ = null; + this.searchQuery_ = null; this.isSearching_ = false; // This will trigger rescan. this.removeFilter('searchbox'); @@ -1421,28 +1365,6 @@ 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.indexOf(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. @@ -1548,6 +1470,87 @@ DirectoryModel.Scanner.prototype.recordMetrics_ = function() { /** * @constructor + * @extends cr.EventTarget + * @param {string} query Query to use in search. + * @param {Array.<Entry>|cr.ui.ArrayDataModel} list Target to put the files. + * @param {function} successCallback Callback to call when (and if) scan + * successfully completed. + * @param {function} errorCallback Callback to call in case of IO error. + * @param {function(Array.<Entry>):void, Function)} preprocessChunk + * Callback to preprocess each chunk of files. + * @param {Object.<string, function(Entry):Boolean>} filters The map of filters + * for file entries. + */ +DirectoryModel.GDataSearchScanner = function(query, list, successCallback, + errorCallback, preprocessChunk, filters) { + this.query_ = query; + this.cancelled_ = false; + this.list_ = list; + this.filters_ = filters; + this.preprocessChunk_ = preprocessChunk; + this.successCallback_ = successCallback; + this.errorCallback_ = errorCallback; +}; + +/** + * Extends EventTarget. + */ +DirectoryModel.GDataSearchScanner.prototype.__proto__ = + cr.EventTarget.prototype; + +/** + * Cancel scanner. + */ +DirectoryModel.GDataSearchScanner.prototype.cancel = function() { + this.cancelled_ = true; +}; + +/** + * Start scanner. + */ +DirectoryModel.GDataSearchScanner.prototype.run = function() { + chrome.fileBrowserPrivate.searchGData(this.query_, + this.onChunkComplete_.bind(this)); +}; + +/** + * @private + * @param {Array.<Entry>} entries File list. + */ +DirectoryModel.GDataSearchScanner.prototype.onChunkComplete_ = + function(entries) { + if (this.cancelled_) + return; + + if (!entries) { + this.errorCallback_(); + return; + } + + if (entries.length == 0) { + this.successCallback_(); + return; + } + + // Splice takes the to-be-spliced-in array as individual parameters, + // rather than as an array, so we need to perform some acrobatics... + var spliceArgs = [].slice.call(entries); + + for (var filterName in this.filters_) { + spliceArgs = spliceArgs.filter(this.filters_[filterName]); + } + + var self = this; + self.preprocessChunk_(spliceArgs, function() { + spliceArgs.unshift(0, 0); // index, deleteCount + self.list_.splice.apply(self.list_, spliceArgs); + + self.successCallback_(); + }); +}; + +/** + * @constructor * @param {DirectoryEntry} root Root entry. * @param {DirectoryModel} directoryModel Model to watch. * @param {VolumeManager} volumeManager Manager to watch. diff --git a/chrome/browser/resources/file_manager/js/file_copy_manager.js b/chrome/browser/resources/file_manager/js/file_copy_manager.js index 79c4724..24d024d 100644 --- a/chrome/browser/resources/file_manager/js/file_copy_manager.js +++ b/chrome/browser/resources/file_manager/js/file_copy_manager.js @@ -537,28 +537,6 @@ FileCopyManager.prototype.serviceNextTaskEntry_ = function( var targetDirEntry = task.targetDirEntry; var originalPath = sourceEntry.fullPath.substr(sourcePath.length + 1); - // If the source entry is GData search result, we should not use the file name - // we get from file entry (this will be in format - // resource_id.original_file_name). Instead, we should use original_file_name. - // Note that if the entry is GData search result, it can only be immediate - // child of |task.sourceDirEntry|, so originalPath should be equal to - // gdataSearchResult.fileName. - var gdataSearchResult = - util.getFileAndDisplayNameForGDataSearchResult(sourceEntry.fullPath); - if (gdataSearchResult && originalPath != gdataSearchResult.displayName) { - if (sourceEntry.isDirectory) { - // We usually register paths relative to sourceDirEntry, but since the - // entries for which we have to do this can only be immediate children of - // the source dir, registering names should be fine. - task.registerRename(gdataSearchResult.fileName, - gdataSearchResult.displayName); - } - // Registered rename paths are appended '/', so we have to change - // |originalPath| for directory entries too. |originalPath| won't be changed - // during applyRenames (at least not by applying just registered rename). - originalPath = gdataSearchResult.displayName; - } - originalPath = task.applyRenames(originalPath); var targetRelativePrefix = originalPath; diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js index 4df3a33..0a6b290 100644 --- a/chrome/browser/resources/file_manager/js/file_manager.js +++ b/chrome/browser/resources/file_manager/js/file_manager.js @@ -1950,7 +1950,7 @@ FileManager.prototype = { var fileName = this.document_.createElement('div'); fileName.className = 'filename-label'; - fileName.textContent = this.getDisplayName_(entry); + fileName.textContent = entry.name; return fileName; }; @@ -2973,12 +2973,18 @@ FileManager.prototype = { }; /** - * Does preprocessing of url list to open before calling |doOpenGallery_|. + * Opens provided urls in the gallery. * - * @param {Array.<string>} urls List of urls to open in the gallery. + * @param {string} selectedUrl Url of the item that should initially be + * selected. + * @param {Array.<string>} urls List of all the urls that will be shown in + * the gallery. */ FileManager.prototype.openGallery_ = function(urls) { + var self = this; + var singleSelection = urls.length == 1; + var selectedUrl; if (singleSelection && FileType.isImage(urls[0])) { // Single image item selected. Pass to the Gallery as a selected. @@ -2994,33 +3000,6 @@ FileManager.prototype = { selectedUrl = urls[0]; } - // TODO(tbarzic): There's probably a better way to do this. - if (this.directoryModel_.isOnGDataSearchDir()) { - var self = this; - var gdataRootUrl = this.directoryModel_.getCurrentRootDirEntry().toURL(); - util.resolveGDataSearchUrls([selectedUrl], gdataRootUrl, - function(resolved) { - util.resolveGDataSearchUrls(urls, gdataRootUrl, - self.doOpenGallery_.bind(self, singleSelection, resolved[0])); - }); - return; - } - this.doOpenGallery_(singleSelection, selectedUrl, urls); - }; - - /** - * Opens provided urls in the gallery. - * - * @param {string} selectedUrl Url of the item that should initially be - * selected. - * @param {Array.<string>} urls List of all the urls that will be shown in - * the gallery. - */ - FileManager.prototype.doOpenGallery_ = function(singleSelection, - selectedUrl, - urls) { - var self = this; - var galleryFrame = this.document_.createElement('iframe'); galleryFrame.className = 'overlay-pane'; galleryFrame.scrolling = 'no'; @@ -3236,21 +3215,12 @@ FileManager.prototype = { this.directoryModel_.getCurrentDirEntry().toURL(); }; - /** - * Return URL of the search directory, current directory or null. - */ - FileManager.prototype.getSearchOrCurrentDirectoryURL = function() { - return this.directoryModel_ && - this.directoryModel_.getSearchOrCurrentDirEntry().toURL(); - }; - FileManager.prototype.deleteEntries = function(entries, force, opt_callback) { if (!force) { var self = this; var msg; if (entries.length == 1) { - var entryName = this.getDisplayName_(entries[0]); - msg = strf('CONFIRM_DELETE_ONE', entryName); + msg = strf('CONFIRM_DELETE_ONE', entries[0].name); } else { msg = strf('CONFIRM_DELETE_SOME', entries.length); } @@ -3310,10 +3280,10 @@ FileManager.prototype = { // We dont want to change the string during preview panel animating away. return; } else if (selection.fileCount == 1 && selection.directoryCount == 0) { - text = this.getDisplayName_(selection.entries[0]); + text = selection.entries[0].name; if (selection.showBytes) text += ', ' + bytes; } else if (selection.fileCount == 0 && selection.directoryCount == 1) { - text = this.getDisplayName_(selection.entries[0]); + text = selection.entries[0].name; } else if (selection.directoryCount == 0) { text = strf('MANY_FILES_SELECTED', selection.fileCount, bytes); // TODO(dgozman): change the string to not contain ", $2". @@ -3383,10 +3353,6 @@ FileManager.prototype = { this.params_.defaultPath = ''; }; - FileManager.prototype.getDisplayName_ = function(entry) { - return this.directoryModel_.getDisplayName(entry.fullPath, entry.name); - }; - /** * Update the UI when the selection model changes. * @@ -3527,9 +3493,7 @@ FileManager.prototype = { }; /** - * Executes directory action (i.e. changes directory). If new directory is a - * search result directory, we'll have to calculate its real path before we - * actually do the operation. + * Executes directory action (i.e. changes directory). * * @param {DirectoryEntry} entry Directory entry to which directory should be * changed. @@ -3542,19 +3506,8 @@ FileManager.prototype = { } else if (mountError == VolumeManager.Error.UNSUPPORTED_FILESYSTEM) { return this.showButter(str('UNSUPPORTED_FILESYSTEM_WARNING')); } - if (!DirectoryModel.isGDataSearchPath(entry.fullPath)) - return this.directoryModel_.changeDirectory(entry.fullPath); - // If we are under gdata search path, the real entries file path may be - // different from |entry.fullPath|. - var self = this; - chrome.fileBrowserPrivate.getPathForDriveSearchResult(entry.toURL(), - function(path) { - // |path| may be undefined if there was an error. If that is the case, - // change to the original file path. - var changeToPath = path; - self.directoryModel_.changeDirectory(changeToPath); - }); + return this.directoryModel_.changeDirectory(entry.fullPath); }; /** @@ -3735,9 +3688,7 @@ FileManager.prototype = { return; function onError(err) { - var entryName = this.getDisplayName_(entry); - nameNode.textContent = entryName; - this.alert.show(strf('ERROR_RENAMING', entryName, + this.alert.show(strf('ERROR_RENAMING', entry.name, getFileErrorString(err.code))); } @@ -3750,7 +3701,7 @@ FileManager.prototype = { if (!exists) { this.directoryModel_.renameEntry(entry, newName, onError.bind(this)); } else { - nameNode.textContent = this.getDisplayName_(entry); + nameNode.textContent = entry.name; var message = isFile ? 'FILE_ALREADY_EXISTS' : 'DIRECTORY_ALREADY_EXISTS'; this.alert.show(strf(message, newName)); @@ -4118,7 +4069,7 @@ FileManager.prototype = { * Performs preprocessing if needed (e.g. for GData). * @param {Object} selection Contains urls, filterIndex and multiple fields. */ - FileManager.prototype.doSelectFilesAndClose_ = function(selection) { + FileManager.prototype.selectFilesAndClose_ = function(selection) { if (!this.isOnGData()) { setTimeout(this.callSelectFilesApiAndClose_.bind(this, selection), 0); return; @@ -4220,25 +4171,6 @@ FileManager.prototype = { }; /** - * Does selection urls list preprocessing and calls |doSelectFilesAndClose_|. - * - * @param {Object} selection Contains urls, filterIndex and multiple fields. - */ - FileManager.prototype.selectFilesAndClose_ = function(selection) { - if (this.directoryModel_.isOnGDataSearchDir()) { - var self = this; - var gdataRootUrl = this.directoryModel_.getCurrentRootDirEntry().toURL(); - util.resolveGDataSearchUrls(selection.urls, gdataRootUrl, - function(resolved) { - selection.urls = resolved; - self.doSelectFilesAndClose_(selection); - }); - return; - } - this.doSelectFilesAndClose_(selection); - }; - - /** * Handle a click of the ok button. * * The ok button has different UI labels depending on the type of dialog, but @@ -4247,13 +4179,13 @@ FileManager.prototype = { * @param {Event} event The click event. */ FileManager.prototype.onOk_ = function(event) { - var currentDirUrl = this.getSearchOrCurrentDirectoryURL(); - - if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/') - currentDirUrl += '/'; - var self = this; if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { + var currentDirUrl = this.getCurrentDirectoryURL(); + + if (currentDirUrl.charAt(currentDirUrl.length - 1) != '/') + currentDirUrl += '/'; + // Save-as doesn't require a valid selection from the list, since // we're going to take the filename from the text input. var filename = this.filenameInput_.value; diff --git a/chrome/browser/resources/file_manager/js/util.js b/chrome/browser/resources/file_manager/js/util.js index 118cefb..b0758a6 100644 --- a/chrome/browser/resources/file_manager/js/util.js +++ b/chrome/browser/resources/file_manager/js/util.js @@ -552,112 +552,6 @@ util.applyTransform = function(element, transform) { }; /** - * Given a list of gdata search result urls, generates a list of urls which - * gdata search result urls reference. - * - * @param {Array.<string>} urls List of gdata search result urls. - * @param {string} rootUrl Root url for resolved urls. Should be gdata root - * url. - * @param {function(Array.<string>)} callback Callback that will be invoked - * when the method finishes. It will be passed list of resolved urls. - */ -util.resolveGDataSearchUrls = function(urls, rootUrl, callback) { - var resolvedUrls = []; - // If the list of urls is empty, there's nothing to do. - if (urls.length == 0) { - callback([]); - return; - } - - // Given relative file path, it will generate escaped file path that will - // be appended to rootUrl to form the resolved url. - function getURIEncodedPath(filePath) { - var components = filePath.split('/'); - // Root url should already contain path's root dir, so clear it. - components[0] = ''; - for (var i = 0; i < components.length; i++) - components[i] = encodeURIComponent(components[i]); - return components.join('/'); - } - - // Resolves single url at |urls[index]| and calls |onResolved| with |index|. - function resolveUrl(index, onResolved) { - chrome.fileBrowserPrivate.getPathForDriveSearchResult(urls[index], - function(filePath) { - if (filePath) { - resolvedUrls.push(rootUrl + getURIEncodedPath(filePath)); - } else { - // If we weren't able to resolve the url, fallback to using - // original url. - resolvedUrls.push(urls[index]); - } - onResolved(index); - }); - } - - // If not all urls are resolved, starts resolving next one, else calls - // callback - function resolveNextOrFinish(lastIndex) { - var nextIndex = lastIndex + 1; - if (nextIndex == urls.length) { - callback(resolvedUrls); - return; - } - resolveUrl(nextIndex, resolveNextOrFinish); - } - - // Start resolving first url. - resolveUrl(0, resolveNextOrFinish); -}; - -/** - * Tests if the given path is a gdata search result path, and if it is, - * returns file's fileName in virtual search file system, its gdata resourceId - * and the display name that should be used when the file is shown in file - * browser. - * - * @param {string} path The potential gdata search result path. - * @return {object.<string, stringi, string>} Object that will contain file's - * fileName, displayName and resourceId; or null if the path is not gdata - * search result path. - */ -util.getFileAndDisplayNameForGDataSearchResult = function(path) { - // Nothing to do if the path is not under gdata search root path. - if (path.indexOf(DirectoryModel.GDATA_SEARCH_ROOT_PATH) != 0) - return null; - - var pathComponents = path.split('/'); - - // Search result should be formatted like: - // gdataSearchRoot/query/result - if (pathComponents.length != - DirectoryModel.GDATA_SEARCH_ROOT_COMPONENTS.length + 2) - return null; - for (var i = 0; - i < DirectoryModel.GDATA_SEARCH_ROOT_COMPONENTS.length; - i++) { - if (pathComponents[i] != DirectoryModel.GDATA_SEARCH_ROOT_COMPONENTS[i]) - return null; - } - - // Search result file name should be formatted like: - // resource_id.referenced_file_name - // We should display referenced file name only. - var result = {}; - result.fileName = pathComponents.pop(); - result.displayName = - result.fileName.slice(result.fileName.indexOf('.') + 1); - result.resourceId = - result.fileName.substr(0, result.fileName.indexOf('.')); - - if (result.fileName.length > 0 && result.displayName.length > 0) { - return result; - } else { - return null; - } -}; - -/** * Makes filesystem: URL from the path. * @param {string} path File or directory path. * @return {string} URL. |