Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1476)

Side by Side Diff: chrome/browser/resources/file_manager/foreground/js/directory_model.js

Issue 151413002: Files.app: Clean DirectoryModel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 'use strict'; 5 'use strict';
6 6
7 // If directory files changes too often, don't rescan directory more than once 7 // If directory files changes too often, don't rescan directory more than once
8 // per specified interval 8 // per specified interval
9 var SIMULTANEOUS_RESCAN_INTERVAL = 1000; 9 var SIMULTANEOUS_RESCAN_INTERVAL = 1000;
10 // Used for operations that require almost instant rescan. 10 // Used for operations that require almost instant rescan.
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 }; 66 };
67 67
68 /** 68 /**
69 * @return {cr.ui.ArrayDataModel} Files in the current directory. 69 * @return {cr.ui.ArrayDataModel} Files in the current directory.
70 */ 70 */
71 DirectoryModel.prototype.getFileList = function() { 71 DirectoryModel.prototype.getFileList = function() {
72 return this.currentFileListContext_.fileList; 72 return this.currentFileListContext_.fileList;
73 }; 73 };
74 74
75 /** 75 /**
76 * Sort the file list.
77 * @param {string} sortField Sort field.
78 * @param {string} sortDirection "asc" or "desc".
79 */
80 DirectoryModel.prototype.sortFileList = function(sortField, sortDirection) {
81 this.getFileList().sort(sortField, sortDirection);
82 };
83
84 /**
85 * @return {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} Selection 76 * @return {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} Selection
86 * in the fileList. 77 * in the fileList.
87 */ 78 */
88 DirectoryModel.prototype.getFileListSelection = function() { 79 DirectoryModel.prototype.getFileListSelection = function() {
89 return this.fileListSelection_; 80 return this.fileListSelection_;
90 }; 81 };
91 82
92 /** 83 /**
93 * @return {?RootType} Root type of current root, or null if not found. 84 * @return {?RootType} Root type of current root, or null if not found.
94 */ 85 */
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 }; 179 };
189 180
190 /** 181 /**
191 * @return {DirectoryEntry} Current directory. 182 * @return {DirectoryEntry} Current directory.
192 */ 183 */
193 DirectoryModel.prototype.getCurrentDirEntry = function() { 184 DirectoryModel.prototype.getCurrentDirEntry = function() {
194 return this.currentDirContents_.getDirectoryEntry(); 185 return this.currentDirContents_.getDirectoryEntry();
195 }; 186 };
196 187
197 /** 188 /**
198 * @return {Array.<Entry>} Array of selected entries.. 189 * @return {Array.<Entry>} Array of selected entries.
199 * @private 190 * @private
200 */ 191 */
201 DirectoryModel.prototype.getSelectedEntries_ = function() { 192 DirectoryModel.prototype.getSelectedEntries_ = function() {
202 var indexes = this.fileListSelection_.selectedIndexes; 193 var indexes = this.fileListSelection_.selectedIndexes;
203 var fileList = this.getFileList(); 194 var fileList = this.getFileList();
204 if (fileList) { 195 if (fileList) {
205 return indexes.map(function(i) { 196 return indexes.map(function(i) {
206 return fileList.item(i); 197 return fileList.item(i);
207 }); 198 });
208 } 199 }
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
636 this.fileListSelection_.endChange(); 627 this.fileListSelection_.endChange();
637 successCallback(newEntry); 628 successCallback(newEntry);
638 } 629 }
639 }.bind(this), function(reason) { 630 }.bind(this), function(reason) {
640 tracker.stop(); 631 tracker.stop();
641 errorCallback(reason); 632 errorCallback(reason);
642 }); 633 });
643 }; 634 };
644 635
645 /** 636 /**
646 * @param {DirectoryEntry} dirEntry The entry of the new directory.
647 * @param {function()=} opt_callback Executed if the directory loads
648 * successfully.
649 * @private
650 */
651 DirectoryModel.prototype.changeDirectoryEntrySilent_ = function(dirEntry,
652 opt_callback) {
653 var onScanComplete = function() {
654 if (opt_callback)
655 opt_callback();
656 // For tests that open the dialog to empty directories, everything
657 // is loaded at this point.
658 chrome.test.sendMessage('directory-change-complete');
659 };
660 this.clearAndScan_(
661 DirectoryContents.createForDirectory(this.currentFileListContext_,
662 dirEntry),
663 onScanComplete.bind(this));
664 };
665
666 /**
667 * Change the current directory to the directory represented by 637 * Change the current directory to the directory represented by
668 * a DirectoryEntry or a fake entry. 638 * a DirectoryEntry or a fake entry.
669 * 639 *
670 * Dispatches the 'directory-changed' event when the directory is successfully 640 * Dispatches the 'directory-changed' event when the directory is successfully
671 * changed. 641 * changed.
672 * 642 *
673 * @param {DirectoryEntry|Object} dirEntry The entry of the new directory to 643 * @param {DirectoryEntry|Object} dirEntry The entry of the new directory to
674 * be opened. 644 * be opened.
675 * @param {function()=} opt_callback Executed if the directory loads 645 * @param {function()=} opt_callback Executed if the directory loads
676 * successfully. 646 * successfully.
677 */ 647 */
678 DirectoryModel.prototype.changeDirectoryEntry = function( 648 DirectoryModel.prototype.changeDirectoryEntry = function(
679 dirEntry, opt_callback) { 649 dirEntry, opt_callback) {
680 if (util.isFakeEntry(dirEntry)) {
681 this.specialSearch(dirEntry);
682 if (opt_callback)
683 opt_callback();
684 return;
685 }
686
687 // Increment the sequence value. 650 // Increment the sequence value.
688 this.changeDirectorySequence_++; 651 this.changeDirectorySequence_++;
652 this.clearSearch_();
689 653
690 this.fileWatcher_.changeWatchedDirectory(dirEntry, function(sequence) { 654 var promise = new Promise(
691 if (this.changeDirectorySequence_ !== sequence) 655 function(onFulfilled, onRejected) {
692 return; 656 this.fileWatcher_.changeWatchedDirectory(dirEntry, onFulfilled);
693 var previous = this.currentDirContents_.getDirectoryEntry(); 657 }.bind(this)).
694 this.clearSearch_();
695 this.changeDirectoryEntrySilent_(dirEntry, opt_callback);
696 658
697 var e = new Event('directory-changed'); 659 then(function(sequence) {
698 e.previousDirEntry = previous; 660 return new Promise(function(onFulfilled, onRejected) {
699 e.newDirEntry = dirEntry; 661 if (this.changeDirectorySequence_ !== sequence)
700 this.dispatchEvent(e); 662 return;
701 }.bind(this, this.changeDirectorySequence_)); 663
664 var newDirectoryContents = this.createDirectoryContents_(
665 this.currentFileListContext_, dirEntry, '');
666 if (!newDirectoryContents)
667 return;
668
669 var event = new Event('directory-changed');
670 event.previousDirEntry = this.currentDirContents_.getDirectoryEntry();
671 event.newDirEntry = dirEntry;
672
673 this.clearAndScan_(newDirectoryContents, opt_callback);
674 this.dispatchEvent(event);
675 }.bind(this));
676 }.bind(this, this.changeDirectorySequence_));
702 }; 677 };
703 678
704 /** 679 /**
705 * Creates an object which could say whether directory has changed while it has 680 * Creates an object which could say whether directory has changed while it has
706 * been active or not. Designed for long operations that should be cancelled 681 * been active or not. Designed for long operations that should be cancelled
707 * if the used change current directory. 682 * if the used change current directory.
708 * @return {Object} Created object. 683 * @return {Object} Created object.
709 */ 684 */
710 DirectoryModel.prototype.createDirectoryChangeTracker = function() { 685 DirectoryModel.prototype.createDirectoryChangeTracker = function() {
711 var tracker = { 686 var tracker = {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
773 DirectoryModel.prototype.selectIndex = function(index) { 748 DirectoryModel.prototype.selectIndex = function(index) {
774 // this.focusCurrentList_(); 749 // this.focusCurrentList_();
775 if (index >= this.getFileList().length) 750 if (index >= this.getFileList().length)
776 return; 751 return;
777 752
778 // If a list bound with the model it will do scrollIndexIntoView(index). 753 // If a list bound with the model it will do scrollIndexIntoView(index).
779 this.fileListSelection_.selectedIndex = index; 754 this.fileListSelection_.selectedIndex = index;
780 }; 755 };
781 756
782 /** 757 /**
783 * Called when VolumeInfoList is updated. 758 * Handles update of VolumeInfoList.
784 * @param {Event} event Event of VolumeInfoList's 'splice'. 759 * @param {Event} event Event of VolumeInfoList's 'splice'.
785 * @private 760 * @private
786 */ 761 */
787 DirectoryModel.prototype.onVolumeInfoListUpdated_ = function(event) { 762 DirectoryModel.prototype.onVolumeInfoListUpdated_ = function(event) {
788 // When the volume where we are is unmounted, fallback to the default volume's 763 // When the volume where we are is unmounted, fallback to the default volume's
789 // root. If current directory path is empty, stop the fallback 764 // root. If current directory path is empty, stop the fallback
790 // since the current directory is initializing now. 765 // since the current directory is initializing now.
791 if (this.getCurrentDirEntry() && 766 if (this.getCurrentDirEntry() &&
792 !this.volumeManager_.getVolumeInfo(this.getCurrentDirEntry())) { 767 !this.volumeManager_.getVolumeInfo(this.getCurrentDirEntry())) {
793 this.volumeManager_.getDefaultDisplayRoot(function(displayRoot) { 768 this.volumeManager_.getDefaultDisplayRoot(function(displayRoot) {
794 this.changeDirectoryEntry(displayRoot); 769 this.changeDirectoryEntry(displayRoot);
795 }.bind(this)); 770 }.bind(this));
796 } 771 }
797 }; 772 };
798 773
799 /** 774 /**
775 * Creates directory contents for the entry and query.
776 *
777 * @param {FileListContext} context File list context.
778 * @param {DirectoryEntry} entry Current directory.
779 * @param {opt_query} opt_query Search query string.
mtomasz 2014/02/04 02:20:12 nit: opt_query -> string=
hirono 2014/02/04 05:53:11 Done.
780 * @return {DirectoryEntry} Directory contents.
mtomasz 2014/02/04 02:20:12 nit: DirectoryEntry -> DirectoryContents
hirono 2014/02/04 05:53:11 Done.
781 * @private
782 */
783 DirectoryModel.prototype.createDirectoryContents_ =
784 function(context, entry, opt_query) {
785 var query = (opt_query || '').trimLeft();
786 var locationInfo = this.volumeManager_.getLocationInfo(entry);
787 if (!locationInfo)
788 return null;
789 var canUseDriveSearch = this.volumeManager_.getDriveConnectionState().type !==
790 util.DriveConnectionType.OFFLINE &&
791 locationInfo.isDriveBased;
792
793 if (query && canUseDriveSearch) {
794 // Drive search.
795 return DirectoryContents.createForDriveSearch(context, entry, query);
796 } else if (query) {
797 // Local search.
798 return DirectoryContents.createForLocalSearch(context, entry, query);
799 } if (util.isFakeEntry(entry)) {
mtomasz 2014/02/04 02:20:12 nit: isFakeEntry -> locationInfo.isSpecialSearchRo
hirono 2014/02/04 05:53:11 Done.
800 // Drive special search.
801 var searchType;
802 switch (locationInfo.rootType) {
803 case RootType.DRIVE_OFFLINE:
804 searchType =
805 DriveMetadataSearchContentScanner.SearchType.SEARCH_OFFLINE;
806 break;
807 case RootType.DRIVE_SHARED_WITH_ME:
808 searchType =
809 DriveMetadataSearchContentScanner.SearchType.SEARCH_SHARED_WITH_ME;
810 break;
811 case RootType.DRIVE_RECENT:
812 searchType =
813 DriveMetadataSearchContentScanner.SearchType.SEARCH_RECENT_FILES;
814 break;
815 default:
816 // Unknown special search entry.
817 throw new Error('Unknown special search type.');
818 }
819 return DirectoryContents.createForDriveMetadataSearch(
820 context,
821 entry,
822 searchType);
823 } else {
824 // Local fetch or search.
825 return DirectoryContents.createForDirectory(context, entry);
826 }
827 };
828
829 /**
800 * Performs search and displays results. The search type is dependent on the 830 * Performs search and displays results. The search type is dependent on the
801 * current directory. If we are currently on drive, server side content search 831 * current directory. If we are currently on drive, server side content search
802 * over drive mount point. If the current directory is not on the drive, file 832 * over drive mount point. If the current directory is not on the drive, file
803 * name search over current directory will be performed. 833 * name search over current directory will be performed.
804 * 834 *
805 * @param {string} query Query that will be searched for. 835 * @param {string} query Query that will be searched for.
806 * @param {function(Event)} onSearchRescan Function that will be called when the 836 * @param {function(Event)} onSearchRescan Function that will be called when the
807 * search directory is rescanned (i.e. search results are displayed). 837 * search directory is rescanned (i.e. search results are displayed).
808 * @param {function()} onClearSearch Function to be called when search state 838 * @param {function()} onClearSearch Function to be called when search state
809 * gets cleared. 839 * gets cleared.
810 * TODO(olege): Change callbacks to events. 840 * TODO(olege): Change callbacks to events.
811 */ 841 */
812 DirectoryModel.prototype.search = function(query, 842 DirectoryModel.prototype.search = function(query,
813 onSearchRescan, 843 onSearchRescan,
814 onClearSearch) { 844 onClearSearch) {
815 query = query.trimLeft();
816
817 this.clearSearch_(); 845 this.clearSearch_();
818
819 var currentDirEntry = this.getCurrentDirEntry(); 846 var currentDirEntry = this.getCurrentDirEntry();
820 if (!currentDirEntry) { 847 if (!currentDirEntry) {
821 // Not yet initialized. Do nothing. 848 // Not yet initialized. Do nothing.
822 return; 849 return;
823 } 850 }
824 851
825 if (!query) { 852 if (!(query || '').trimLeft()) {
826 if (this.isSearching()) { 853 if (this.isSearching()) {
827 var newDirContents = DirectoryContents.createForDirectory( 854 var newDirContents = DirectoryContents.createForDirectory(
828 this.currentFileListContext_, 855 this.currentFileListContext_,
829 this.currentDirContents_.getLastNonSearchDirectoryEntry()); 856 currentDirEntry);
830 this.clearAndScan_(newDirContents); 857 this.clearAndScan_(newDirContents);
831 } 858 }
832 return; 859 return;
833 } 860 }
834 861
862 var newDirContents = this.createDirectoryContents_(
863 this.currentFileListContext_, currentDirEntry, query);
864 if (!newDirContents)
865 return;
866
835 this.onSearchCompleted_ = onSearchRescan; 867 this.onSearchCompleted_ = onSearchRescan;
836 this.onClearSearch_ = onClearSearch; 868 this.onClearSearch_ = onClearSearch;
837
838 this.addEventListener('scan-completed', this.onSearchCompleted_); 869 this.addEventListener('scan-completed', this.onSearchCompleted_);
839
840 // If we are offline, let's fallback to file name search inside dir.
841 // A search initiated from directories in Drive or special search results
842 // should trigger Drive search.
843 var newDirContents;
844 var isDriveOffline = this.volumeManager_.getDriveConnectionState().type ===
845 util.DriveConnectionType.OFFLINE;
846 var locationInfo = this.volumeManager_.getLocationInfo(currentDirEntry);
847 if (!isDriveOffline && locationInfo && locationInfo.isDriveBased) {
848 // Drive search is performed over the whole drive, so pass drive root as
849 // |directoryEntry|.
850 newDirContents = DirectoryContents.createForDriveSearch(
851 this.currentFileListContext_,
852 currentDirEntry,
853 this.currentDirContents_.getLastNonSearchDirectoryEntry(),
854 query);
855 } else {
856 newDirContents = DirectoryContents.createForLocalSearch(
857 this.currentFileListContext_, currentDirEntry, query);
858 }
859 this.clearAndScan_(newDirContents); 870 this.clearAndScan_(newDirContents);
860 }; 871 };
861 872
862 /** 873 /**
863 * Performs special search and displays results. e.g. Drive files available
864 * offline, shared-with-me files, recently modified files.
865 * @param {Object} fakeEntry Fake entry representing a special search.
866 * @param {string=} opt_query Query string used for the search.
867 */
868 DirectoryModel.prototype.specialSearch = function(fakeEntry, opt_query) {
869 var query = opt_query || '';
870
871 // Increment the sequence value.
872 this.changeDirectorySequence_++;
873
874 this.clearSearch_();
875 this.onSearchCompleted_ = null;
876 this.onClearSearch_ = null;
877
878 // Obtains a volume information.
879 // TODO(hirono): Obtain the proper profile's volume information.
880 var volumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo(
881 util.VolumeType.DRIVE);
882 if (!volumeInfo) {
883 // It seems that the volume is already unmounted or drive is disable.
884 return;
885 }
886
887 var onDriveDirectoryResolved = function(sequence, driveRoot) {
888 if (this.changeDirectorySequence_ !== sequence)
889 return;
890
891 var locationInfo = this.volumeManager_.getLocationInfo(fakeEntry);
892 if (!locationInfo)
893 return;
894
895 var searchOption;
896 switch (locationInfo.rootType) {
897 case RootType.DRIVE_OFFLINE:
898 searchOption =
899 DriveMetadataSearchContentScanner.SearchType.SEARCH_OFFLINE;
900 break;
901 case RootType.DRIVE_SHARED_WITH_ME:
902 searchOption =
903 DriveMetadataSearchContentScanner.SearchType.SEARCH_SHARED_WITH_ME;
904 break;
905 case RootType.DRIVE_RECENT:
906 searchOption =
907 DriveMetadataSearchContentScanner.SearchType.SEARCH_RECENT_FILES;
908 break;
909 default:
910 // Unknown special search entry.
911 throw new Error('Unknown special search type.');
912 }
913
914 var newDirContents = DirectoryContents.createForDriveMetadataSearch(
915 this.currentFileListContext_,
916 fakeEntry, driveRoot, query, searchOption);
917 var previous = this.currentDirContents_.getDirectoryEntry();
918 this.clearAndScan_(newDirContents);
919
920 var e = new Event('directory-changed');
921 e.previousDirEntry = previous;
922 e.newDirEntry = fakeEntry;
923 this.dispatchEvent(e);
924 }.bind(this, this.changeDirectorySequence_);
925
926 volumeInfo.resolveDisplayRoot(
927 onDriveDirectoryResolved /* success */, function() {} /* failed */);
928 };
929
930 /**
931 * In case the search was active, remove listeners and send notifications on 874 * In case the search was active, remove listeners and send notifications on
932 * its canceling. 875 * its canceling.
933 * @private 876 * @private
934 */ 877 */
935 DirectoryModel.prototype.clearSearch_ = function() { 878 DirectoryModel.prototype.clearSearch_ = function() {
936 if (!this.isSearching()) 879 if (!this.isSearching())
937 return; 880 return;
938 881
939 if (this.onSearchCompleted_) { 882 if (this.onSearchCompleted_) {
940 this.removeEventListener('scan-completed', this.onSearchCompleted_); 883 this.removeEventListener('scan-completed', this.onSearchCompleted_);
941 this.onSearchCompleted_ = null; 884 this.onSearchCompleted_ = null;
942 } 885 }
943 886
944 if (this.onClearSearch_) { 887 if (this.onClearSearch_) {
945 this.onClearSearch_(); 888 this.onClearSearch_();
946 this.onClearSearch_ = null; 889 this.onClearSearch_ = null;
947 } 890 }
948 }; 891 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698