Chromium Code Reviews| 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..1f415c9062c73c44add584bb16e2608dec0b4b3c 100644 |
| --- a/chrome/browser/resources/file_manager/js/directory_contents.js |
| +++ b/chrome/browser/resources/file_manager/js/directory_contents.js |
| @@ -5,6 +5,329 @@ |
| 'use strict'; |
| /** |
| + * Scanner of the entries. |
|
mtomasz
2013/10/01 02:13:44
@constructor is missing
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +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. |
|
mtomasz
2013/10/01 02:13:44
nit: Please add a new line after the description i
hidehiko
2013/10/01 04:12:23
Done.
|
| + * 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.startScan = function( |
| + entriesCallback, successCallback, errorCallback) { |
| +}; |
| + |
| +/** |
| + * Request cancelling of the running scan. When the cancelling is done, |
| + * an error will be reported from errorCallback passed to startScan(). |
| + */ |
| +ContentScanner.prototype.cancel = function() { |
| + this.cancelled_ = true; |
| +}; |
| + |
| +/** |
| + * Scanner of the entries in a directory. |
| + * @param {DirectoryEntry} entry The directory to be read. |
| + * @extends {ContentScanner} |
|
mtomasz
2013/10/01 02:13:44
@constructor is missing
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +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. |
|
mtomasz
2013/10/01 02:13:44
@override is missing
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +DirectoryContentScanner.prototype.startScan = 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. |
| + * @extends {ContentScanner} |
|
mtomasz
2013/10/01 02:13:44
ditto (@constructor)
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +function DriveSearchContentScanner(query) { |
| + ContentScanner.call(this); |
| + this.query_ = query; |
| +} |
| + |
| +/** |
| + * Extends ContentScanner. |
| + */ |
| +DriveSearchContentScanner.prototype.__proto__ = ContentScanner.prototype; |
| + |
| +/** |
| + * Delay to be used for drive search scan, in order to reduce the number of |
| + * server requests while user is typeing the query. |
|
mtomasz
2013/10/01 02:13:44
nit: typeing -> typing
nit: in milliseconds (we al
hidehiko
2013/10/01 04:12:23
Done.
|
| + * @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. |
|
mtomasz
2013/10/01 02:13:44
nit: ditto (@override)
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +DriveSearchContentScanner.prototype.startScan = 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. |
|
mtomasz
2013/10/01 02:13:44
ditto
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +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. |
|
mtomasz
2013/10/01 02:13:44
ditto here and in other places
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +LocalSearchContentScanner.prototype.startScan = 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. |
| + * @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. |
|
mtomasz
2013/10/01 02:13:44
@enum {string} missing
hidehiko
2013/10/01 04:12:23
Done.
|
| + */ |
| +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. |
| + */ |
| +DriveMetadataSearchContentScanner.prototype.startScan = function( |
|
mtomasz
2013/10/01 02:13:44
optional: how about just scan() instead of startSc
hidehiko
2013/10/01 04:12:23
Done.
|
| + 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 +342,7 @@ function FileFilter(metadataCache, showHidden) { |
| * @private |
| */ |
| this.metadataCache_ = metadataCache; |
| + |
| /** |
| * @type Object.<string, Function> |
| * @private |
| @@ -102,6 +426,7 @@ function FileListContext(fileFilter, metadataCache) { |
| * @type {cr.ui.ArrayDataModel} |
| */ |
| this.fileList = new cr.ui.ArrayDataModel([]); |
| + |
| /** |
| * @type {MetadataCache} |
| */ |
| @@ -125,11 +450,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 +495,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 +529,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 +640,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 +692,10 @@ 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); |
| + this.scanner_ = new DirectoryContentScanner(this.entry_); |
|
mtomasz
2013/10/01 02:36:39
Do we need to create a new instance of scanner eve
hidehiko
2013/10/01 04:12:23
Good point.
In the existing code, scan must be cal
mtomasz
2013/10/01 04:39:55
Can you please add either (1) a TODO line or (2):
hidehiko
2013/10/01 05:28:17
Done.
|
| + this.scanner_.startScan(this.onNewEntries.bind(this), |
| + this.onScanCompleted.bind(this), |
| + this.onScanError.bind(this)); |
| }; |
| /** |
| @@ -409,6 +705,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 +723,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 +739,6 @@ function DirectoryContentsDriveSearch(context, |
| this.directoryEntry_ = dirEntry; |
| this.previousDirectoryEntry_ = previousDirEntry; |
| this.query_ = query; |
| - this.nextFeed_ = ''; |
| - this.done_ = false; |
| - this.fetchedResultsNum_ = 0; |
| } |
| /** |
| @@ -507,54 +784,13 @@ 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); |
| + this.scanner_ = new DriveSearchContentScanner(this.query_); |
|
mtomasz
2013/10/01 02:36:39
Same here.
hidehiko
2013/10/01 04:12:23
Ack.
|
| + this.scanner_.startScan(this.onNewEntries.bind(this), |
| + this.onScanCompleted.bind(this), |
| + this.onScanError.bind(this)); |
| }; |
| /** |
| - * 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); |
| -}; |
| - |
| - |
| -/** |
| * @param {FileListContext} context File list context. |
| * @param {DirectoryEntry} dirEntry Current directory. |
| * @param {string} query Search query. |
| @@ -564,7 +800,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 +846,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_.startScan(this.onNewEntries.bind(this), |
| + this.onScanCompleted.bind(this), |
| + this.onScanError.bind(this)); |
| }; |
| /** |
| @@ -686,7 +861,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 +924,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_.startScan(this.onNewEntries.bind(this), |
| + this.onScanCompleted.bind(this), |
| + this.onScanError.bind(this)); |
| }; |