Index: chrome/browser/resources/file_manager/js/directory_contents.js |
diff --git a/chrome/browser/resources/file_manager/js/directory_contents.js b/chrome/browser/resources/file_manager/js/directory_contents.js |
index be916c1e51fc38a9e89076d78b8fefe0b1cf7b94..fece6f207fd0335fe38c46a933683be436821ae8 100644 |
--- a/chrome/browser/resources/file_manager/js/directory_contents.js |
+++ b/chrome/browser/resources/file_manager/js/directory_contents.js |
@@ -5,6 +5,341 @@ |
'use strict'; |
/** |
+ * Scanner of the entries. |
+ * @constructor |
+ */ |
+function ContentScanner() { |
+ this.cancelled_ = false; |
+} |
+ |
+/** |
+ * Starts to scan the entries. For example, starts to read the entries in a |
+ * directory, or starts to search with some query on a file system. |
+ * Derived classes must override this method. |
+ * |
+ * @param {function(Array.<Entry>)} entriesCallback Called when some chunk of |
+ * entries are read. This can be called a couple of times until the |
+ * completion. |
+ * @param {function()} successCallback Called when the scan is completed |
+ * successfully. |
+ * @param {function(FileError)} errorCallback Called an error occurs. |
+ */ |
+ContentScanner.prototype.scan = function( |
+ entriesCallback, successCallback, errorCallback) { |
+}; |
+ |
+/** |
+ * Request cancelling of the running scan. When the cancelling is done, |
+ * an error will be reported from errorCallback passed to scan(). |
+ */ |
+ContentScanner.prototype.cancel = function() { |
+ this.cancelled_ = true; |
+}; |
+ |
+/** |
+ * Scanner of the entries in a directory. |
+ * @param {DirectoryEntry} entry The directory to be read. |
+ * @constructor |
+ * @extends {ContentScanner} |
+ */ |
+function DirectoryContentScanner(entry) { |
+ ContentScanner.call(this); |
+ this.entry_ = entry; |
+} |
+ |
+/** |
+ * Extends ContentScanner. |
+ */ |
+DirectoryContentScanner.prototype.__proto__ = ContentScanner.prototype; |
+ |
+/** |
+ * Starts to read the entries in the directory. |
+ * @param {function(Array.<Entry>)} entriesCallback Called when some chunk of |
+ * entries are read. This can be called a couple of times until the |
+ * completion. |
+ * @param {function()} successCallback Called when the scan is completed |
+ * successfully. |
+ * @param {function(FileError)} errorCallback Called an error occurs. |
+ * @override |
+ */ |
+DirectoryContentScanner.prototype.scan = function( |
+ entriesCallback, successCallback, errorCallback) { |
+ if (!this.entry_ || this.entry_ === DirectoryModel.fakeDriveEntry_) { |
+ // If entry is not specified or a fake, we cannot read it. |
+ errorCallback(util.createFileError(FileError.INVALID_MODIFICATION_ERR)); |
+ return; |
+ } |
+ |
+ metrics.startInterval('DirectoryScan'); |
+ var reader = this.entry_.createReader(); |
+ var readEntries = function() { |
+ reader.readEntries( |
+ function(entries) { |
+ if (this.cancelled_) { |
+ errorCallback(util.createFileError(FileError.ABORT_ERR)); |
+ return; |
+ } |
+ |
+ if (entries.length === 0) { |
+ // All entries are read. |
+ metrics.recordInterval('DirectoryScan'); |
+ successCallback(); |
+ return; |
+ } |
+ |
+ entriesCallback(entries); |
+ readEntries(); |
+ }.bind(this), |
+ errorCallback); |
+ }.bind(this); |
+ readEntries(); |
+}; |
+ |
+/** |
+ * Scanner of the entries for the search results on Drive File System. |
+ * @param {string} query The query string. |
+ * @constructor |
+ * @extends {ContentScanner} |
+ */ |
+function DriveSearchContentScanner(query) { |
+ ContentScanner.call(this); |
+ this.query_ = query; |
+} |
+ |
+/** |
+ * Extends ContentScanner. |
+ */ |
+DriveSearchContentScanner.prototype.__proto__ = ContentScanner.prototype; |
+ |
+/** |
+ * Delay in milliseconds to be used for drive search scan, in order to reduce |
+ * the number of server requests while user is typing the query. |
+ * @type {number} |
+ * @private |
+ * @const |
+ */ |
+DriveSearchContentScanner.SCAN_DELAY_ = 200; |
+ |
+/** |
+ * Maximum number of results which is shown on the search. |
+ * @type {number} |
+ * @private |
+ * @const |
+ */ |
+DriveSearchContentScanner.MAX_RESULTS_ = 100; |
+ |
+/** |
+ * Starts to search on Drive File System. |
+ * @param {function(Array.<Entry>)} entriesCallback Called when some chunk of |
+ * entries are read. This can be called a couple of times until the |
+ * completion. |
+ * @param {function()} successCallback Called when the scan is completed |
+ * successfully. |
+ * @param {function(FileError)} errorCallback Called an error occurs. |
+ * @override |
+ */ |
+DriveSearchContentScanner.prototype.scan = function( |
+ entriesCallback, successCallback, errorCallback) { |
+ var numReadEntries = 0; |
+ var readEntries = function(nextFeed) { |
+ chrome.fileBrowserPrivate.searchDrive( |
+ {query: this.query_, nextFeed: nextFeed}, |
+ function(entries, nextFeed) { |
+ if (this.cancelled_) { |
+ errorCallback(util.createFileError(FileError.ABORT_ERR)); |
+ return; |
+ } |
+ |
+ // TODO(tbarzic): Improve error handling. |
+ if (!entries) { |
+ console.error('Drive search encountered an error.'); |
+ errorCallback(util.createFileError( |
+ FileError.INVALID_MODIFICATION_ERR)); |
+ return; |
+ } |
+ |
+ var numRemainingEntries = |
+ DriveSearchContentScanner.MAX_RESULTS_ - numReadEntries; |
+ if (entries.length >= numRemainingEntries) { |
+ // The limit is hit, so quit the scan here. |
+ entries = entries.slice(0, numRemainingEntries); |
+ nextFeed = ''; |
+ } |
+ |
+ numReadEntries += entries.length; |
+ if (entries.length > 0) |
+ entriesCallback(entries); |
+ |
+ if (nextFeed === '') |
+ successCallback(); |
+ else |
+ readEntries(nextFeed); |
+ }.bind(this)); |
+ }.bind(this); |
+ |
+ // Let's give another search a chance to cancel us before we begin. |
+ setTimeout( |
+ function() { |
+ // Check cancelled state before read the entries. |
+ if (this.cancelled_) { |
+ errorCallback(util.createFileError(FileError.ABORT_ERR)); |
+ return; |
+ } |
+ readEntries(''); |
+ }.bind(this), |
+ DriveSearchContentScanner.SCAN_DELAY_); |
+}; |
+ |
+/** |
+ * Scanner of the entries of the file name search on the directory tree, whose |
+ * root is entry. |
+ * @param {DirectoryEntry} entry The root of the search target directory tree. |
+ * @param {string} query The query of the search. |
+ * @constructor |
+ * @extends {ContentScanner} |
+ */ |
+function LocalSearchContentScanner(entry, query) { |
+ ContentScanner.call(this); |
+ this.entry_ = entry; |
+ this.query_ = query.toLowerCase(); |
+} |
+ |
+/** |
+ * Extedns ContentScanner. |
+ */ |
+LocalSearchContentScanner.prototype.__proto__ = ContentScanner.prototype; |
+ |
+/** |
+ * Starts the file name search. |
+ * @param {function(Array.<Entry>)} entriesCallback Called when some chunk of |
+ * entries are read. This can be called a couple of times until the |
+ * completion. |
+ * @param {function()} successCallback Called when the scan is completed |
+ * successfully. |
+ * @param {function(FileError)} errorCallback Called an error occurs. |
+ * @override |
+ */ |
+LocalSearchContentScanner.prototype.scan = function( |
+ entriesCallback, successCallback, errorCallback) { |
+ var numRunningTasks = 0; |
+ var error = null; |
+ var maybeRunCallback = function() { |
+ if (numRunningTasks === 0) { |
+ if (this.cancelled_) |
+ errorCallback(util.createFileError(FileError.ABORT_ERR)); |
+ else if (error) |
+ errorCallback(error); |
+ else |
+ successCallback(); |
+ } |
+ }.bind(this); |
+ |
+ var processEntry = function(entry) { |
+ numRunningTasks++; |
+ var onError = function(fileError) { |
+ if (!error) |
+ error = fileError; |
+ numRunningTasks--; |
+ maybeRunCallback(); |
+ }; |
+ |
+ var onSuccess = function(entries) { |
+ if (this.cancelled_ || error || entries.length === 0) { |
+ numRunningTasks--; |
+ maybeRunCallback(); |
+ return; |
+ } |
+ |
+ // Filters by the query, and if found, run entriesCallback. |
+ var foundEntries = entries.filter(function(entry) { |
+ return entry.name.toLowerCase().indexOf(this.query_) >= 0; |
+ }.bind(this)); |
+ if (foundEntries.length > 0) |
+ entriesCallback(foundEntries); |
+ |
+ // Start to process sub directories. |
+ for (var i = 0; i < entries.length; i++) { |
+ if (entries[i].isDirectory) |
+ processEntry(entries[i]); |
+ } |
+ |
+ // Read remaining entries. |
+ reader.readEntries(onSuccess, onError); |
+ }.bind(this); |
+ |
+ var reader = entry.createReader(); |
+ reader.readEntries(onSuccess, onError); |
+ }.bind(this); |
+ |
+ processEntry(this.entry_); |
+}; |
+ |
+/** |
+ * Scanner of the entries for the metadata seaerch on Drive File System. |
+ * @param {string} query The query of the search. |
+ * @param {DriveMetadataSearchContentScanner.SearchType} searchType The option |
+ * of the search. |
+ * @constructor |
+ * @extends {ContentScanner} |
+ */ |
+function DriveMetadataSearchContentScanner(query, searchType) { |
+ ContentScanner.call(this); |
+ this.query_ = query; |
+ this.searchType_ = searchType; |
+} |
+ |
+/** |
+ * Extends ContentScanner. |
+ */ |
+DriveMetadataSearchContentScanner.prototype.__proto__ = |
+ ContentScanner.prototype; |
+ |
+/** |
+ * The search types on the Drive File System. |
+ * @enum {string} |
+ */ |
+DriveMetadataSearchContentScanner.SearchType = Object.freeze({ |
+ SEARCH_ALL: 'ALL', |
+ SEARCH_SHARED_WITH_ME: 'SHARED_WITH_ME', |
+ SEARCH_RECENT_FILES: 'EXCLUDE_DIRECTORIES', |
+ SEARCH_OFFLINE: 'OFFLINE' |
+}); |
+ |
+/** |
+ * Starts to metadata-search on Drive File System. |
+ * @param {function(Array.<Entry>)} entriesCallback Called when some chunk of |
+ * entries are read. This can be called a couple of times until the |
+ * completion. |
+ * @param {function()} successCallback Called when the scan is completed |
+ * successfully. |
+ * @param {function(FileError)} errorCallback Called an error occurs. |
+ * @override |
+ */ |
+DriveMetadataSearchContentScanner.prototype.scan = function( |
+ entriesCallback, successCallback, errorCallback) { |
+ chrome.fileBrowserPrivate.searchDriveMetadata( |
+ {query: this.query_, types: this.searchType_, maxResults: 500}, |
+ function(results) { |
+ if (this.cancelled_) { |
+ errorCallback(util.createFileError(FileError.ABORT_ERR)); |
+ return; |
+ } |
+ |
+ if (!results) { |
+ console.error('Drive search encountered an error.'); |
+ errorCallback(util.createFileError( |
+ FileError.INVALID_MODIFICATION_ERR)); |
+ return; |
+ } |
+ |
+ var entries = results.map(function(result) { return result.entry; }); |
+ if (entries.length > 0) |
+ entriesCallback(entries); |
+ successCallback(); |
+ }.bind(this)); |
+}; |
+ |
+/** |
* This class manages filters and determines a file should be shown or not. |
* When filters are changed, a 'changed' event is fired. |
* |
@@ -19,6 +354,7 @@ function FileFilter(metadataCache, showHidden) { |
* @private |
*/ |
this.metadataCache_ = metadataCache; |
+ |
/** |
* @type Object.<string, Function> |
* @private |
@@ -102,6 +438,7 @@ function FileListContext(fileFilter, metadataCache) { |
* @type {cr.ui.ArrayDataModel} |
*/ |
this.fileList = new cr.ui.ArrayDataModel([]); |
+ |
/** |
* @type {MetadataCache} |
*/ |
@@ -125,11 +462,8 @@ function FileListContext(fileFilter, metadataCache) { |
function DirectoryContents(context) { |
this.context_ = context; |
this.fileList_ = context.fileList; |
- this.scanCompletedCallback_ = null; |
- this.scanFailedCallback_ = null; |
+ this.prefetchMetadataQueue_ = new AsyncUtil.Queue(); |
this.scanCancelled_ = false; |
- this.allChunksFetched_ = false; |
- this.pendingMetadataRequests_ = 0; |
this.fileList_.prepareSort = this.prepareSort_.bind(this); |
} |
@@ -173,8 +507,7 @@ DirectoryContents.prototype.replaceContextFileList = function() { |
* @return {boolean} If the scan is active. |
*/ |
DirectoryContents.prototype.isScanning = function() { |
- return !this.scanCancelled_ && |
- (!this.allChunksFetched_ || this.pendingMetadataRequests_ > 0); |
+ return this.scanner_ || this.prefetchMetadataQueue_.isRunning(); |
}; |
/** |
@@ -208,40 +541,84 @@ DirectoryContents.prototype.scan = function() { |
}; |
/** |
- * Read next chunk of results from DirectoryReader. |
- * @protected |
- */ |
-DirectoryContents.prototype.readNextChunk = function() { |
- throw 'Not implemented.'; |
-}; |
- |
-/** |
- * Cancel the running scan. |
+ * Cancels the running scan. |
*/ |
DirectoryContents.prototype.cancelScan = function() { |
if (this.scanCancelled_) |
return; |
this.scanCancelled_ = true; |
+ if (this.scanner_) |
+ this.scanner_.cancel(); |
+ |
+ this.prefetchMetadataQueue_.cancel(); |
cr.dispatchSimpleEvent(this, 'scan-cancelled'); |
}; |
+/** |
+ * Called when the scanning by scanner_ is done. |
+ * @protected |
+ */ |
+DirectoryContents.prototype.onScanCompleted = function() { |
+ this.scanner_ = null; |
+ if (this.scanCancelled_) |
+ return; |
+ |
+ this.prefetchMetadataQueue_.run(function(callback) { |
+ cr.dispatchSimpleEvent(this, 'scan-completed'); |
+ if (!this.isSearch() && |
+ this.getDirectoryEntry().fullPath === RootDirectory.DOWNLOADS) |
+ metrics.recordMediumCount('DownloadsCount', this.fileList_.length); |
+ callback(); |
+ }.bind(this)); |
+}; |
/** |
* Called in case scan has failed. Should send the event. |
* @protected |
*/ |
-DirectoryContents.prototype.onError = function() { |
- cr.dispatchSimpleEvent(this, 'scan-failed'); |
+DirectoryContents.prototype.onScanError = function() { |
+ this.scanner_ = null; |
+ if (this.scanCancelled_) |
+ return; |
+ |
+ this.prefetchMetadataQueue_.run(function(callback) { |
+ cr.dispatchSimpleEvent(this, 'scan-failed'); |
+ callback(); |
+ }.bind(this)); |
}; |
/** |
- * Called in case scan has completed succesfully. Should send the event. |
+ * Called when some chunk of entries are read by scanner. |
+ * @param {Array.<Entry>} entries The list of the scanned entries. |
* @protected |
*/ |
-DirectoryContents.prototype.lastChunkReceived = function() { |
- this.allChunksFetched_ = true; |
- if (!this.scanCancelled_ && this.pendingMetadataRequests_ === 0) |
- cr.dispatchSimpleEvent(this, 'scan-completed'); |
+DirectoryContents.prototype.onNewEntries = function(entries) { |
+ if (this.scanCancelled_) |
+ return; |
+ |
+ var entriesFiltered = [].filter.call( |
+ entries, this.context_.fileFilter.filter.bind(this.context_.fileFilter)); |
+ |
+ // Because the prefetchMetadata can be slow, throttling by splitting entries |
+ // into smaller chunks to reduce UI latency. |
+ // TODO(hidehiko,mtomasz): This should be handled in MetadataCache. |
+ var MAX_CHUNK_SIZE = 50; |
+ for (var i = 0; i < entriesFiltered.length; i += MAX_CHUNK_SIZE) { |
+ var chunk = entriesFiltered.slice(i, i + MAX_CHUNK_SIZE); |
+ this.prefetchMetadataQueue_.run(function(chunk, callback) { |
+ this.prefetchMetadata(chunk, function() { |
+ if (this.scanCancelled_) { |
+ // Do nothing if the scanning is cancelled. |
+ callback(); |
+ return; |
+ } |
+ |
+ this.fileList_.push.apply(this.fileList_, chunk); |
+ cr.dispatchSimpleEvent(this, 'scan-updated'); |
+ callback(); |
+ }.bind(this)); |
+ }.bind(this, chunk)); |
+ } |
}; |
/** |
@@ -275,36 +652,6 @@ DirectoryContents.prototype.reloadMetadata = function(entries, callback) { |
}; |
/** |
- * @protected |
- * @param {Array.<Entry>} entries File list. |
- */ |
-DirectoryContents.prototype.onNewEntries = function(entries) { |
- if (this.scanCancelled_) |
- return; |
- |
- var entriesFiltered = [].filter.call( |
- entries, this.context_.fileFilter.filter.bind(this.context_.fileFilter)); |
- |
- var onPrefetched = function() { |
- this.pendingMetadataRequests_--; |
- if (this.scanCancelled_) |
- return; |
- this.fileList_.push.apply(this.fileList_, entriesFiltered); |
- |
- if (this.pendingMetadataRequests_ === 0 && this.allChunksFetched_) |
- cr.dispatchSimpleEvent(this, 'scan-completed'); |
- else |
- cr.dispatchSimpleEvent(this, 'scan-updated'); |
- |
- if (!this.allChunksFetched_) |
- this.readNextChunk(); |
- }; |
- |
- this.pendingMetadataRequests_++; |
- this.prefetchMetadata(entriesFiltered, onPrefetched.bind(this)); |
-}; |
- |
-/** |
* @param {string} name Directory name. |
* @param {function(DirectoryEntry)} successCallback Called on success. |
* @param {function(FileError)} errorCallback On error. |
@@ -357,49 +704,12 @@ DirectoryContentsBasic.prototype.getLastNonSearchDirectoryEntry = function() { |
* Start directory scan. |
*/ |
DirectoryContentsBasic.prototype.scan = function() { |
- if (!this.entry_ || this.entry_ === DirectoryModel.fakeDriveEntry_) { |
- this.lastChunkReceived(); |
- return; |
- } |
- |
- metrics.startInterval('DirectoryScan'); |
- this.reader_ = this.entry_.createReader(); |
- this.readNextChunk(); |
-}; |
- |
-/** |
- * Read next chunk of results from DirectoryReader. |
- * @protected |
- */ |
-DirectoryContentsBasic.prototype.readNextChunk = function() { |
- this.reader_.readEntries(this.onChunkComplete_.bind(this), |
- this.onError.bind(this)); |
-}; |
- |
-/** |
- * @param {Array.<Entry>} entries File list. |
- * @private |
- */ |
-DirectoryContentsBasic.prototype.onChunkComplete_ = function(entries) { |
- if (this.scanCancelled_) |
- return; |
- |
- if (entries.length == 0) { |
- this.lastChunkReceived(); |
- this.recordMetrics_(); |
- return; |
- } |
- |
- this.onNewEntries(entries); |
-}; |
- |
-/** |
- * @private |
- */ |
-DirectoryContentsBasic.prototype.recordMetrics_ = function() { |
- metrics.recordInterval('DirectoryScan'); |
- if (this.entry_.fullPath === RootDirectory.DOWNLOADS) |
- metrics.recordMediumCount('DownloadsCount', this.fileList_.length); |
+ // TODO(hidehiko,mtomasz): this scan method must be called at most once. |
+ // Remove such a limitation. |
+ this.scanner_ = new DirectoryContentScanner(this.entry_); |
+ this.scanner_.scan(this.onNewEntries.bind(this), |
+ this.onScanCompleted.bind(this), |
+ this.onScanError.bind(this)); |
}; |
/** |
@@ -409,6 +719,8 @@ DirectoryContentsBasic.prototype.recordMetrics_ = function() { |
*/ |
DirectoryContentsBasic.prototype.createDirectory = function( |
name, successCallback, errorCallback) { |
+ // TODO(hidehiko): createDirectory should not be the part of |
+ // DirectoryContent. |
if (!this.entry_) { |
errorCallback(util.createFileError(FileError.INVALID_MODIFICATION_ERR)); |
return; |
@@ -425,24 +737,6 @@ DirectoryContentsBasic.prototype.createDirectory = function( |
}; |
/** |
- * Delay to be used for drive search scan. |
- * The goal is to reduce the number of server requests when user is typing the |
- * query. |
- * |
- * @type {number} |
- * @const |
- */ |
-DirectoryContentsDriveSearch.SCAN_DELAY = 200; |
- |
-/** |
- * Maximum number of results which is shown on the search. |
- * |
- * @type {number} |
- * @const |
- */ |
-DirectoryContentsDriveSearch.MAX_RESULTS = 100; |
- |
-/** |
* @param {FileListContext} context File list context. |
* @param {DirectoryEntry} dirEntry Current directory. |
* @param {DirectoryEntry} previousDirEntry DirectoryEntry that was current |
@@ -459,9 +753,6 @@ function DirectoryContentsDriveSearch(context, |
this.directoryEntry_ = dirEntry; |
this.previousDirectoryEntry_ = previousDirEntry; |
this.query_ = query; |
- this.nextFeed_ = ''; |
- this.done_ = false; |
- this.fetchedResultsNum_ = 0; |
} |
/** |
@@ -507,53 +798,12 @@ DirectoryContentsDriveSearch.prototype.getLastNonSearchDirectoryEntry = |
* Start directory scan. |
*/ |
DirectoryContentsDriveSearch.prototype.scan = function() { |
- // Let's give another search a chance to cancel us before we begin. |
- setTimeout(this.readNextChunk.bind(this), |
- DirectoryContentsDriveSearch.SCAN_DELAY); |
-}; |
- |
-/** |
- * All the results are read in one chunk, so when we try to read second chunk, |
- * it means we're done. |
- */ |
-DirectoryContentsDriveSearch.prototype.readNextChunk = function() { |
- if (this.scanCancelled_) |
- return; |
- |
- if (this.done_) { |
- this.lastChunkReceived(); |
- return; |
- } |
- |
- var searchCallback = (function(entries, nextFeed) { |
- // TODO(tbarzic): Improve error handling. |
- if (!entries) { |
- console.error('Drive search encountered an error.'); |
- this.lastChunkReceived(); |
- return; |
- } |
- this.nextFeed_ = nextFeed; |
- var remaining = |
- DirectoryContentsDriveSearch.MAX_RESULTS - this.fetchedResultsNum_; |
- if (entries.length >= remaining) { |
- entries = entries.slice(0, remaining); |
- this.nextFeed_ = ''; |
- } |
- this.fetchedResultsNum_ += entries.length; |
- |
- this.done_ = (this.nextFeed_ == ''); |
- |
- this.onNewEntries(entries); |
- }).bind(this); |
- |
- var searchParams = { |
- 'query': this.query_, |
- 'nextFeed': this.nextFeed_ |
- }; |
- chrome.fileBrowserPrivate.searchDrive(searchParams, searchCallback); |
+ this.scanner_ = new DriveSearchContentScanner(this.query_); |
+ this.scanner_.scan(this.onNewEntries.bind(this), |
+ this.onScanCompleted.bind(this), |
+ this.onScanError.bind(this)); |
}; |
- |
/** |
* @param {FileListContext} context File list context. |
* @param {DirectoryEntry} dirEntry Current directory. |
@@ -564,7 +814,7 @@ DirectoryContentsDriveSearch.prototype.readNextChunk = function() { |
function DirectoryContentsLocalSearch(context, dirEntry, query) { |
DirectoryContents.call(this, context); |
this.directoryEntry_ = dirEntry; |
- this.query_ = query.toLowerCase(); |
+ this.query_ = query; |
} |
/** |
@@ -610,72 +860,11 @@ DirectoryContentsLocalSearch.prototype.getLastNonSearchDirectoryEntry = |
* 'scan-failed' event will be fired upon completion. |
*/ |
DirectoryContentsLocalSearch.prototype.scan = function() { |
- this.pendingScans_ = 0; |
- this.scanDirectory_(this.directoryEntry_); |
-}; |
- |
-/** |
- * Scan a directory. |
- * @param {DirectoryEntry} entry A directory to scan. |
- * @private |
- */ |
-DirectoryContentsLocalSearch.prototype.scanDirectory_ = function(entry) { |
- this.pendingScans_++; |
- var reader = entry.createReader(); |
- var found = []; |
- |
- var onChunkComplete = function(entries) { |
- if (this.scanCancelled_) |
- return; |
- |
- if (entries.length === 0) { |
- if (found.length > 0) |
- this.onNewEntries(found); |
- this.pendingScans_--; |
- if (this.pendingScans_ === 0) |
- this.lastChunkReceived(); |
- return; |
- } |
- |
- for (var i = 0; i < entries.length; i++) { |
- if (entries[i].name.toLowerCase().indexOf(this.query_) != -1) { |
- found.push(entries[i]); |
- } |
- |
- if (entries[i].isDirectory) |
- this.scanDirectory_(entries[i]); |
- } |
- |
- getNextChunk(); |
- }.bind(this); |
- |
- var getNextChunk = function() { |
- reader.readEntries(onChunkComplete, this.onError.bind(this)); |
- }.bind(this); |
- |
- getNextChunk(); |
-}; |
- |
-/** |
- * We get results for each directory in one go in scanDirectory_. |
- */ |
-DirectoryContentsLocalSearch.prototype.readNextChunk = function() { |
-}; |
- |
-/** |
- * List of search types for DirectoryContentsDriveSearch. |
- * TODO(haruki): SHARED_WITH_ME support for searchDriveMetadata is not yet |
- * implemented. Update this when it's done. |
- * SEARCH_ALL uses no filtering. |
- * SEARCH_SHARED_WITH_ME searches for the shared-with-me entries. |
- * SEARCH_RECENT_FILES searches for recently accessed file entries. |
- * @enum {number} |
- */ |
-DirectoryContentsDriveSearchMetadata.SearchType = { |
- SEARCH_ALL: 0, |
- SEARCH_SHARED_WITH_ME: 1, |
- SEARCH_RECENT_FILES: 2, |
- SEARCH_OFFLINE: 3 |
+ this.scanner_ = |
+ new LocalSearchContentScanner(this.directoryEntry_, this.query_); |
+ this.scanner_.scan(this.onNewEntries.bind(this), |
+ this.onScanCompleted.bind(this), |
+ this.onScanError.bind(this)); |
}; |
/** |
@@ -686,7 +875,7 @@ DirectoryContentsDriveSearchMetadata.SearchType = { |
* @param {DirectoryEntry} fakeDirEntry Fake directory representing the set of |
* result files. This serves as a top directory for this search. |
* @param {string} query Search query to filter the files. |
- * @param {DirectoryContentsDriveSearchMetadata.SearchType} searchType |
+ * @param {DriveMetadataSearchContentScanner.SearchType} searchType |
* Type of search. searchDriveMetadata will restricts the entries based on |
* the given search type. |
* @constructor |
@@ -749,56 +938,9 @@ DirectoryContentsDriveSearchMetadata.prototype.getLastNonSearchDirectoryEntry = |
* 'scan-failed' event will be fired upon completion. |
*/ |
DirectoryContentsDriveSearchMetadata.prototype.scan = function() { |
- this.readNextChunk(); |
-}; |
- |
-/** |
- * All the results are read in one chunk, so when we try to read second chunk, |
- * it means we're done. |
- */ |
-DirectoryContentsDriveSearchMetadata.prototype.readNextChunk = function() { |
- if (this.scanCancelled_) |
- return; |
- |
- if (this.done_) { |
- this.lastChunkReceived(); |
- return; |
- } |
- |
- var searchCallback = (function(results, nextFeed) { |
- if (!results) { |
- console.error('Drive search encountered an error.'); |
- this.lastChunkReceived(); |
- return; |
- } |
- this.done_ = true; |
- |
- var entries = results.map(function(r) { return r.entry; }); |
- this.onNewEntries(entries); |
- this.lastChunkReceived(); |
- }).bind(this); |
- |
- var type; |
- switch (this.searchType_) { |
- case DirectoryContentsDriveSearchMetadata.SearchType.SEARCH_ALL: |
- type = 'ALL'; |
- break; |
- case DirectoryContentsDriveSearchMetadata.SearchType.SEARCH_SHARED_WITH_ME: |
- type = 'SHARED_WITH_ME'; |
- break; |
- case DirectoryContentsDriveSearchMetadata.SearchType.SEARCH_RECENT_FILES: |
- type = 'EXCLUDE_DIRECTORIES'; |
- break; |
- case DirectoryContentsDriveSearchMetadata.SearchType.SEARCH_OFFLINE: |
- type = 'OFFLINE'; |
- break; |
- default: |
- throw Error('Unknown search type: ' + this.searchType_); |
- } |
- var searchParams = { |
- 'query': this.query_, |
- 'types': type, |
- 'maxResults': 500 |
- }; |
- chrome.fileBrowserPrivate.searchDriveMetadata(searchParams, searchCallback); |
+ this.scanner_ = |
+ new DriveMetadataSearchContentScanner(this.query_, this.searchType_); |
+ this.scanner_.scan(this.onNewEntries.bind(this), |
+ this.onScanCompleted.bind(this), |
+ this.onScanError.bind(this)); |
}; |