Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / file_manager / foreground / js / directory_contents.js
index 867aae0..23581f2 100644 (file)
@@ -58,9 +58,10 @@ DirectoryContentScanner.prototype.__proto__ = ContentScanner.prototype;
  */
 DirectoryContentScanner.prototype.scan = function(
     entriesCallback, successCallback, errorCallback) {
-  if (!this.entry_ || this.entry_ === DirectoryModel.fakeDriveEntry_) {
+  if (!this.entry_ || util.isFakeEntry(this.entry_)) {
     // If entry is not specified or a fake, we cannot read it.
-    errorCallback(util.createFileError(FileError.INVALID_MODIFICATION_ERR));
+    errorCallback(util.createDOMError(
+        util.FileError.INVALID_MODIFICATION_ERR));
     return;
   }
 
@@ -70,7 +71,7 @@ DirectoryContentScanner.prototype.scan = function(
     reader.readEntries(
         function(entries) {
           if (this.cancelled_) {
-            errorCallback(util.createFileError(FileError.ABORT_ERR));
+            errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
             return;
           }
 
@@ -134,15 +135,15 @@ DriveSearchContentScanner.prototype.scan = function(
         {query: this.query_, nextFeed: nextFeed},
         function(entries, nextFeed) {
           if (this.cancelled_) {
-            errorCallback(util.createFileError(FileError.ABORT_ERR));
+            errorCallback(util.createDOMError(util.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));
+            errorCallback(util.createDOMError(
+                util.FileError.INVALID_MODIFICATION_ERR));
             return;
           }
 
@@ -170,7 +171,7 @@ DriveSearchContentScanner.prototype.scan = function(
       function() {
         // Check cancelled state before read the entries.
         if (this.cancelled_) {
-          errorCallback(util.createFileError(FileError.ABORT_ERR));
+          errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
           return;
         }
         readEntries('');
@@ -208,7 +209,7 @@ LocalSearchContentScanner.prototype.scan = function(
   var maybeRunCallback = function() {
     if (numRunningTasks === 0) {
       if (this.cancelled_)
-        errorCallback(util.createFileError(FileError.ABORT_ERR));
+        errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
       else if (error)
         errorCallback(error);
       else
@@ -258,15 +259,13 @@ LocalSearchContentScanner.prototype.scan = function(
 
 /**
  * Scanner of the entries for the metadata search 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) {
+function DriveMetadataSearchContentScanner(searchType) {
   ContentScanner.call(this);
-  this.query_ = query;
   this.searchType_ = searchType;
 }
 
@@ -294,17 +293,17 @@ DriveMetadataSearchContentScanner.SearchType = Object.freeze({
 DriveMetadataSearchContentScanner.prototype.scan = function(
     entriesCallback, successCallback, errorCallback) {
   chrome.fileBrowserPrivate.searchDriveMetadata(
-      {query: this.query_, types: this.searchType_, maxResults: 500},
+      {query: '', types: this.searchType_, maxResults: 500},
       function(results) {
         if (this.cancelled_) {
-          errorCallback(util.createFileError(FileError.ABORT_ERR));
+          errorCallback(util.createDOMError(util.FileError.ABORT_ERR));
           return;
         }
 
         if (!results) {
           console.error('Drive search encountered an error.');
-          errorCallback(util.createFileError(
-              FileError.INVALID_MODIFICATION_ERR));
+          errorCallback(util.createDOMError(
+              util.FileError.INVALID_MODIFICATION_ERR));
           return;
         }
 
@@ -437,28 +436,25 @@ function FileListContext(fileFilter, metadataCache) {
  * @param {boolean} isSearch True for search directory contents, otherwise
  *     false.
  * @param {DirectoryEntry} directoryEntry The entry of the current directory.
- * @param {DirectoryEntry} lastNonSearchDirectoryEntry The entry of the last
- *     non-search directory.
  * @param {function():ContentScanner} scannerFactory The factory to create
  *     ContentScanner instance.
  * @constructor
  * @extends {cr.EventTarget}
  */
-function DirectoryContents(context, isSearch, directoryEntry,
-                           lastNonSearchDirectoryEntry,
+function DirectoryContents(context,
+                           isSearch,
+                           directoryEntry,
                            scannerFactory) {
   this.context_ = context;
   this.fileList_ = context.fileList;
 
   this.isSearch_ = isSearch;
   this.directoryEntry_ = directoryEntry;
-  this.lastNonSearchDirectoryEntry_ = lastNonSearchDirectoryEntry;
 
   this.scannerFactory_ = scannerFactory;
   this.scanner_ = null;
   this.prefetchMetadataQueue_ = new AsyncUtil.Queue();
   this.scanCancelled_ = false;
-  this.fileList_.prepareSort = this.prepareSort_.bind(this);
 }
 
 /**
@@ -472,8 +468,10 @@ DirectoryContents.prototype.__proto__ = cr.EventTarget.prototype;
  */
 DirectoryContents.prototype.clone = function() {
   return new DirectoryContents(
-      this.context_, this.isSearch_, this.directoryEntry_,
-      this.lastNonSearchDirectoryEntry_, this.scannerFactory_);
+      this.context_,
+      this.isSearch_,
+      this.directoryEntry_,
+      this.scannerFactory_);
 };
 
 /**
@@ -481,8 +479,11 @@ DirectoryContents.prototype.clone = function() {
  * @param {Array|cr.ui.ArrayDataModel} fileList The new file list.
  */
 DirectoryContents.prototype.setFileList = function(fileList) {
-  this.fileList_ = fileList;
-  this.fileList_.prepareSort = this.prepareSort_.bind(this);
+  if (fileList instanceof cr.ui.ArrayDataModel)
+    this.fileList_ = fileList;
+  else
+    this.fileList_ = new cr.ui.ArrayDataModel(fileList);
+  this.context_.metadataCache.setCacheSize(this.fileList_.length);
 };
 
 /**
@@ -491,11 +492,12 @@ DirectoryContents.prototype.setFileList = function(fileList) {
  */
 DirectoryContents.prototype.replaceContextFileList = function() {
   if (this.context_.fileList !== this.fileList_) {
-    var spliceArgs = [].slice.call(this.fileList_);
+    var spliceArgs = this.fileList_.slice();
     var fileList = this.context_.fileList;
     spliceArgs.unshift(0, fileList.length);
     fileList.splice.apply(fileList, spliceArgs);
     this.fileList_ = fileList;
+    this.context_.metadataCache.setCacheSize(this.fileList_.length);
   }
 };
 
@@ -522,23 +524,34 @@ DirectoryContents.prototype.getDirectoryEntry = function() {
 };
 
 /**
- * @return {DirectoryEntry} A DirectoryEntry for the last non search contents.
- */
-DirectoryContents.prototype.getLastNonSearchDirectoryEntry = function() {
-  return this.lastNonSearchDirectoryEntry_;
-};
-
-/**
  * Start directory scan/search operation. Either 'scan-completed' or
  * 'scan-failed' event will be fired upon completion.
  */
 DirectoryContents.prototype.scan = function() {
+  /**
+   * Invoked when the scanning is completed successfully.
+   * @this {DirectoryContents}
+   */
+  function completionCallback() {
+    this.onScanFinished_();
+    this.onScanCompleted_();
+  }
+
+  /**
+   * Invoked when the scanning is finished but is not completed due to error.
+   * @this {DirectoryContents}
+   */
+  function errorCallback() {
+    this.onScanFinished_();
+    this.onScanError_();
+  }
+
   // TODO(hidehiko,mtomasz): this scan method must be called at most once.
   // Remove such a limitation.
   this.scanner_ = this.scannerFactory_();
   this.scanner_.scan(this.onNewEntries_.bind(this),
-                     this.onScanCompleted_.bind(this),
-                     this.onScanError_.bind(this));
+                     completionCallback.bind(this),
+                     errorCallback.bind(this));
 };
 
 /**
@@ -551,25 +564,49 @@ DirectoryContents.prototype.cancelScan = function() {
   if (this.scanner_)
     this.scanner_.cancel();
 
+  this.onScanFinished_();
+
   this.prefetchMetadataQueue_.cancel();
   cr.dispatchSimpleEvent(this, 'scan-cancelled');
 };
 
 /**
- * Called when the scanning by scanner_ is done.
+ * Called when the scanning by scanner_ is done, even when the scanning is
+ * succeeded or failed. This is called before completion (or error) callback.
+ *
  * @private
  */
-DirectoryContents.prototype.onScanCompleted_ = function() {
+DirectoryContents.prototype.onScanFinished_ = function() {
   this.scanner_ = null;
+
+  this.prefetchMetadataQueue_.run(function(callback) {
+    // TODO(yoshiki): Here we should fire the update event of changed
+    // items. Currently we have a method this.fileList_.updateIndex() to
+    // fire an event, but this method takes only 1 argument and invokes sort
+    // one by one. It is obviously time wasting. Instead, we call sort
+    // directory.
+    // In future, we should implement a good method like updateIndexes and
+    // use it here.
+    var status = this.fileList_.sortStatus;
+    if (status)
+      this.fileList_.sort(status.field, status.direction);
+
+    callback();
+  }.bind(this));
+};
+
+/**
+ * Called when the scanning by scanner_ is succeeded.
+ * @private
+ */
+DirectoryContents.prototype.onScanCompleted_ = function() {
   if (this.scanCancelled_)
     return;
 
   this.prefetchMetadataQueue_.run(function(callback) {
-    if (!this.isSearch() &&
-        this.getDirectoryEntry().fullPath === RootDirectory.DOWNLOADS)
-      metrics.recordMediumCount('DownloadsCount', this.fileList_.length);
     // Call callback first, so isScanning() returns false in the event handlers.
     callback();
+
     cr.dispatchSimpleEvent(this, 'scan-completed');
   }.bind(this));
 };
@@ -579,7 +616,6 @@ DirectoryContents.prototype.onScanCompleted_ = function() {
  * @private
  */
 DirectoryContents.prototype.onScanError_ = function() {
-  this.scanner_ = null;
   if (this.scanCancelled_)
     return;
 
@@ -602,6 +638,12 @@ DirectoryContents.prototype.onNewEntries_ = function(entries) {
   var entriesFiltered = [].filter.call(
       entries, this.context_.fileFilter.filter.bind(this.context_.fileFilter));
 
+  // Update the filelist without waiting the metadata.
+  this.fileList_.push.apply(this.fileList_, entriesFiltered);
+  cr.dispatchSimpleEvent(this, 'scan-updated');
+
+  this.context_.metadataCache.setCacheSize(this.fileList_.length);
+
   // 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.
@@ -616,7 +658,6 @@ DirectoryContents.prototype.onNewEntries_ = function(entries) {
           return;
         }
 
-        this.fileList_.push.apply(this.fileList_, chunk);
         cr.dispatchSimpleEvent(this, 'scan-updated');
         callback();
       }.bind(this));
@@ -625,57 +666,11 @@ DirectoryContents.prototype.onNewEntries_ = function(entries) {
 };
 
 /**
- * Cache necessary data before a sort happens.
- *
- * This is called by the table code before a sort happens, so that we can
- * go fetch data for the sort field that we may not have yet.
- * @param {string} field Sort field.
- * @param {function(Object)} callback Called when done.
- * @private
- */
-DirectoryContents.prototype.prepareSort_ = function(field, callback) {
-  this.prefetchMetadata(this.fileList_.slice(), callback);
-};
-
-/**
  * @param {Array.<Entry>} entries Files.
  * @param {function(Object)} callback Callback on done.
  */
 DirectoryContents.prototype.prefetchMetadata = function(entries, callback) {
-  this.context_.metadataCache.get(entries, 'filesystem', callback);
-};
-
-/**
- * @param {Array.<Entry>} entries Files.
- * @param {function(Object)} callback Callback on done.
- */
-DirectoryContents.prototype.reloadMetadata = function(entries, callback) {
-  this.context_.metadataCache.clear(entries, '*');
-  this.context_.metadataCache.get(entries, 'filesystem', callback);
-};
-
-/**
- * @param {string} name Directory name.
- * @param {function(DirectoryEntry)} successCallback Called on success.
- * @param {function(FileError)} errorCallback On error.
- */
-DirectoryContents.prototype.createDirectory = function(
-    name, successCallback, errorCallback) {
-  // TODO(hidehiko): createDirectory should not be the part of
-  // DirectoryContent.
-  if (this.isSearch_ || !this.directoryEntry_) {
-    errorCallback(util.createFileError(FileError.INVALID_MODIFICATION_ERR));
-    return;
-  }
-
-  var onSuccess = function(newEntry) {
-    this.reloadMetadata([newEntry], function() {
-      successCallback(newEntry);
-    });
-  };
-
-  this.directoryEntry_.getDirectory(name, {create: true, exclusive: true},
-                                    onSuccess.bind(this), errorCallback);
+  this.context_.metadataCache.get(entries, 'filesystem|drive', callback);
 };
 
 /**
@@ -690,7 +685,6 @@ DirectoryContents.createForDirectory = function(context, directoryEntry) {
       context,
       false,  // Non search.
       directoryEntry,
-      directoryEntry,
       function() {
         return new DirectoryContentScanner(directoryEntry);
       });
@@ -702,18 +696,15 @@ DirectoryContents.createForDirectory = function(context, directoryEntry) {
  *
  * @param {FileListContext} context File list context.
  * @param {DirectoryEntry} directoryEntry The current directory entry.
- * @param {DirectoryEntry} previousDirectoryEntry The DirectoryEntry that was
- *     current before the search.
  * @param {string} query Search query.
  * @return {DirectoryContents} Created DirectoryContents instance.
  */
 DirectoryContents.createForDriveSearch = function(
-    context, directoryEntry, previousDirectoryEntry, query) {
+    context, directoryEntry, query) {
   return new DirectoryContents(
       context,
       true,  // Search.
       directoryEntry,
-      previousDirectoryEntry,
       function() {
         return new DriveSearchContentScanner(query);
       });
@@ -734,7 +725,6 @@ DirectoryContents.createForLocalSearch = function(
       context,
       true,  // Search.
       directoryEntry,
-      directoryEntry,
       function() {
         return new LocalSearchContentScanner(directoryEntry, query);
       });
@@ -748,21 +738,18 @@ DirectoryContents.createForLocalSearch = function(
  * @param {DirectoryEntry} fakeDirectoryEntry Fake directory entry representing
  *     the set of result entries. This serves as a top directory for the
  *     search.
- * @param {DirectoryEntry} driveDirectoryEntry Directory for the actual drive.
- * @param {string} query Search query.
  * @param {DriveMetadataSearchContentScanner.SearchType} searchType The type of
  *     the search. The scanner will restricts the entries based on the given
  *     type.
  * @return {DirectoryContents} Created DirectoryContents instance.
  */
 DirectoryContents.createForDriveMetadataSearch = function(
-    context, fakeDirectoryEntry, driveDirectoryEntry, query, searchType) {
+    context, fakeDirectoryEntry, searchType) {
   return new DirectoryContents(
       context,
       true,  // Search
       fakeDirectoryEntry,
-      driveDirectoryEntry,
       function() {
-        return new DriveMetadataSearchContentScanner(query, searchType);
+        return new DriveMetadataSearchContentScanner(searchType);
       });
 };