[Files app] ES6 class for ui/file_manager/file_manager/foreground/js/search_controller.js
Bug: 778674
Change-Id: Id6a3c5a48af4085a74282e7f3f89cc95dd426e0e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1630075
Commit-Queue: Luciano Pacheco <lucmult@chromium.org>
Auto-Submit: Luciano Pacheco <lucmult@chromium.org>
Reviewed-by: François Degros <fdegros@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663476}
diff --git a/ui/file_manager/file_manager/foreground/js/search_controller.js b/ui/file_manager/file_manager/foreground/js/search_controller.js
index 17965a4..c0986c7 100644
--- a/ui/file_manager/file_manager/foreground/js/search_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/search_controller.js
@@ -4,53 +4,45 @@
/**
* Controller for searching.
- * @param {!SearchBox} searchBox Search box UI element.
- * @param {!LocationLine} locationLine Location line UI element.
- * @param {!DirectoryModel} directoryModel Directory model.
- * @param {!TaskController} taskController Task controller to execute the
- * selected item.
- * @constructor
*/
-function SearchController(
- searchBox, locationLine, directoryModel, volumeManager, taskController) {
+class SearchController {
/**
- * @type {SearchBox}
- * @private
+ * @param {!SearchBox} searchBox Search box UI element.
+ * @param {!LocationLine} locationLine Location line UI element.
+ * @param {!DirectoryModel} directoryModel Directory model.
+ * @param {!TaskController} taskController Task controller to execute the
+ * selected item.
*/
- this.searchBox_ = searchBox;
+ constructor(
+ searchBox, locationLine, directoryModel, volumeManager, taskController) {
+ /** @const @private {!SearchBox} */
+ this.searchBox_ = searchBox;
- /**
- * @type {LocationLine}
- * @private
- */
- this.locationLine_ = locationLine;
+ /** @const @private {!LocationLine} */
+ this.locationLine_ = locationLine;
- /**
- * @type {DirectoryModel}
- * @private
- */
- this.directoryModel_ = directoryModel;
+ /** @const @private {!DirectoryModel} */
+ this.directoryModel_ = directoryModel;
- /**
- * @type {VolumeManager}
- * @private
- */
- this.volumeManager_ = volumeManager;
+ /** @const @private {!VolumeManager} */
+ this.volumeManager_ = volumeManager;
- /**
- * @type {!TaskController}
- * @private
- */
- this.taskController_ = taskController;
+ /** @const @private {!TaskController} */
+ this.taskController_ = taskController;
- searchBox.addEventListener(
- SearchBox.EventType.TEXT_CHANGE, this.onTextChange_.bind(this));
- searchBox.addEventListener(
- SearchBox.EventType.ITEM_SELECT, this.onItemSelect_.bind(this));
- directoryModel.addEventListener('directory-changed', this.clear.bind(this));
-}
+ /** @private {string} */
+ this.lastAutocompleteQuery_ = '';
-SearchController.prototype = {
+ /** @private {boolean} */
+ this.autocompleteSuggestionsBusy_ = false;
+
+ searchBox.addEventListener(
+ SearchBox.EventType.TEXT_CHANGE, this.onTextChange_.bind(this));
+ searchBox.addEventListener(
+ SearchBox.EventType.ITEM_SELECT, this.onItemSelect_.bind(this));
+ directoryModel.addEventListener('directory-changed', this.clear.bind(this));
+ }
+
/**
* Obtains current directory's locaiton info.
* @type {EntryLocation}
@@ -59,7 +51,7 @@
get currentLocationInfo_() {
const entry = this.directoryModel_.getCurrentDirEntry();
return entry && this.volumeManager_.getLocationInfo(entry);
- },
+ }
/**
* Whether the current directory is on drive or not.
@@ -69,191 +61,193 @@
const currentLocationInfo = this.currentLocationInfo_;
return currentLocationInfo && currentLocationInfo.isDriveBased;
}
-};
-/**
- * Clears the search state.
- * @param {Event=} opt_event when called from "directory-changed" event.
- */
-SearchController.prototype.clear = function(opt_event) {
- this.directoryModel_.clearLastSearchQuery();
- this.searchBox_.clear();
- // Only update visibility if |clear| is called from "directory-changed" event.
- if (opt_event) {
- // My Files currently doesn't implement search so let's hide it.
- const isMyFiles =
- (opt_event.newDirEntry &&
- opt_event.newDirEntry.rootType ===
- VolumeManagerCommon.RootType.MY_FILES);
- this.searchBox_.setHidden(isMyFiles);
- }
-};
-
-/**
- * Handles text change event.
- * @private
- */
-SearchController.prototype.onTextChange_ = function() {
- const searchString = this.searchBox_.inputElement.value.trimLeft();
-
- // On drive, incremental search is not invoked since we have an auto-
- // complete suggestion instead.
- if (!this.isOnDrive_) {
- this.search_(searchString);
- return;
+ /**
+ * Clears the search state.
+ * @param {Event=} opt_event when called from "directory-changed" event.
+ */
+ clear(opt_event) {
+ this.directoryModel_.clearLastSearchQuery();
+ this.searchBox_.clear();
+ // Only update visibility if |clear| is called from "directory-changed"
+ // event.
+ if (opt_event) {
+ // My Files currently doesn't implement search so let's hide it.
+ const isMyFiles =
+ (opt_event.newDirEntry &&
+ opt_event.newDirEntry.rootType ===
+ VolumeManagerCommon.RootType.MY_FILES);
+ this.searchBox_.setHidden(isMyFiles);
+ }
}
- // When the search text is changed, finishes the search and showes back
- // the last directory by passing an empty string to
- // {@code DirectoryModel.search()}.
- if (this.directoryModel_.isSearching() &&
- this.directoryModel_.getLastSearchQuery() != searchString) {
- this.directoryModel_.search('', () => {}, () => {});
- }
+ /**
+ * Handles text change event.
+ * @private
+ */
+ onTextChange_() {
+ const searchString = this.searchBox_.inputElement.value.trimLeft();
- this.requestAutocompleteSuggestions_();
-};
-
-/**
- * Updates autocompletion items.
- * @private
- */
-SearchController.prototype.requestAutocompleteSuggestions_ = function() {
- // Remember the most recent query. If there is an other request in progress,
- // then it's result will be discarded and it will call a new request for
- // this query.
- const searchString = this.searchBox_.inputElement.value.trimLeft();
- this.lastAutocompleteQuery_ = searchString;
- if (this.autocompleteSuggestionsBusy_) {
- return;
- }
-
- // Clear search if the query empty.
- if (!searchString) {
- this.searchBox_.autocompleteList.suggestions = [];
- return;
- }
-
- // Add header item.
- const headerItem = /** @type {SearchItem} */ (
- {isHeaderItem: true, searchQuery: searchString});
- if (!this.searchBox_.autocompleteList.dataModel ||
- this.searchBox_.autocompleteList.dataModel.length == 0) {
- this.searchBox_.autocompleteList.suggestions = [headerItem];
- } else {
- // Updates only the head item to prevent a flickering on typing.
- this.searchBox_.autocompleteList.dataModel.splice(0, 1, headerItem);
- }
-
- // The autocomplete list should be resized and repositioned here as the
- // search box is resized when it's focused.
- this.searchBox_.autocompleteList.syncWidthAndPositionToInput();
- this.autocompleteSuggestionsBusy_ = true;
-
- chrome.fileManagerPrivate.searchDriveMetadata(
- {
- query: searchString,
- types: 'ALL',
- maxResults: 4,
- },
- suggestions => {
- this.autocompleteSuggestionsBusy_ = false;
-
- // Discard results for previous requests and fire a new search
- // for the most recent query.
- if (searchString != this.lastAutocompleteQuery_) {
- this.requestAutocompleteSuggestions_();
- return;
- }
-
- // Keeps the items in the suggestion list.
- this.searchBox_.autocompleteList.suggestions =
- [headerItem].concat(suggestions);
- });
-};
-
-/**
- * Opens the currently selected suggestion item.
- * @private
- */
-SearchController.prototype.onItemSelect_ = function() {
- const selectedItem = this.searchBox_.autocompleteList.selectedItem;
-
- // Clear the current auto complete list.
- this.lastAutocompleteQuery_ = '';
- this.searchBox_.autocompleteList.suggestions = [];
-
- // If the entry is the search item or no entry is selected, just change to
- // the search result.
- if (!selectedItem || selectedItem.isHeaderItem) {
- const query = selectedItem ? selectedItem.searchQuery :
- this.searchBox_.inputElement.value;
- this.search_(query);
- return;
- }
-
- // Clear the search box if an item except for the search item is
- // selected. Eventually the following directory change clears the search box,
- // but if the selected item is located just under /drive/other, the current
- // directory will not changed. For handling the case, and for improving
- // response time, clear the text manually here.
- this.clear();
-
- // If the entry is a directory, just change the directory.
- const entry = selectedItem.entry;
- if (entry.isDirectory) {
- this.directoryModel_.changeDirectoryEntry(entry);
- return;
- }
-
- // Change the current directory to the directory that contains the
- // selected file. Note that this is necessary for an image or a video,
- // which should be opened in the gallery mode, as the gallery mode
- // requires the entry to be in the current directory model. For
- // consistency, the current directory is always changed regardless of
- // the file type.
- entry.getParent(parentEntry => {
- // Check if the parent entry points /drive/other or not.
- // If so it just opens the file.
- const locationInfo = this.volumeManager_.getLocationInfo(parentEntry);
- if (!locationInfo ||
- (locationInfo.isRootEntry &&
- locationInfo.rootType === VolumeManagerCommon.RootType.DRIVE_OTHER)) {
- this.taskController_.executeEntryTask(entry);
+ // On drive, incremental search is not invoked since we have an auto-
+ // complete suggestion instead.
+ if (!this.isOnDrive_) {
+ this.search_(searchString);
return;
}
- // If the parent entry can be /drive/other.
- this.directoryModel_.changeDirectoryEntry(parentEntry, () => {
- this.directoryModel_.selectEntry(entry);
- this.taskController_.executeEntryTask(entry);
- });
- });
-};
-/**
- * Search files and update the list with the search result.
- * @param {string} searchString String to be searched with.
- * @private
- */
-SearchController.prototype.search_ = function(searchString) {
- const onSearchRescan = function() {
- // If the current location is somewhere in Drive, all files in Drive can
- // be listed as search results regardless of current location.
- // In this case, showing current location is confusing, so use the Drive
- // root "My Drive" as the current location.
- if (this.isOnDrive_) {
- const locationInfo = this.currentLocationInfo_;
- const rootEntry = locationInfo.volumeInfo.displayRoot;
- if (rootEntry) {
- this.locationLine_.show(rootEntry);
- }
+ // When the search text is changed, finishes the search and showes back
+ // the last directory by passing an empty string to
+ // {@code DirectoryModel.search()}.
+ if (this.directoryModel_.isSearching() &&
+ this.directoryModel_.getLastSearchQuery() != searchString) {
+ this.directoryModel_.search('', () => {}, () => {});
}
- };
- const onClearSearch = function() {
- this.locationLine_.show(this.directoryModel_.getCurrentDirEntry());
- };
+ this.requestAutocompleteSuggestions_();
+ }
- this.directoryModel_.search(
- searchString, onSearchRescan.bind(this), onClearSearch.bind(this));
-};
+ /**
+ * Updates autocompletion items.
+ * @private
+ */
+ requestAutocompleteSuggestions_() {
+ // Remember the most recent query. If there is an other request in progress,
+ // then it's result will be discarded and it will call a new request for
+ // this query.
+ const searchString = this.searchBox_.inputElement.value.trimLeft();
+ this.lastAutocompleteQuery_ = searchString;
+ if (this.autocompleteSuggestionsBusy_) {
+ return;
+ }
+
+ // Clear search if the query empty.
+ if (!searchString) {
+ this.searchBox_.autocompleteList.suggestions = [];
+ return;
+ }
+
+ // Add header item.
+ const headerItem = /** @type {SearchItem} */ (
+ {isHeaderItem: true, searchQuery: searchString});
+ if (!this.searchBox_.autocompleteList.dataModel ||
+ this.searchBox_.autocompleteList.dataModel.length == 0) {
+ this.searchBox_.autocompleteList.suggestions = [headerItem];
+ } else {
+ // Updates only the head item to prevent a flickering on typing.
+ this.searchBox_.autocompleteList.dataModel.splice(0, 1, headerItem);
+ }
+
+ // The autocomplete list should be resized and repositioned here as the
+ // search box is resized when it's focused.
+ this.searchBox_.autocompleteList.syncWidthAndPositionToInput();
+ this.autocompleteSuggestionsBusy_ = true;
+
+ chrome.fileManagerPrivate.searchDriveMetadata(
+ {
+ query: searchString,
+ types: 'ALL',
+ maxResults: 4,
+ },
+ suggestions => {
+ this.autocompleteSuggestionsBusy_ = false;
+
+ // Discard results for previous requests and fire a new search
+ // for the most recent query.
+ if (searchString != this.lastAutocompleteQuery_) {
+ this.requestAutocompleteSuggestions_();
+ return;
+ }
+
+ // Keeps the items in the suggestion list.
+ this.searchBox_.autocompleteList.suggestions =
+ [headerItem].concat(suggestions);
+ });
+ }
+
+ /**
+ * Opens the currently selected suggestion item.
+ * @private
+ */
+ onItemSelect_() {
+ const selectedItem = this.searchBox_.autocompleteList.selectedItem;
+
+ // Clear the current auto complete list.
+ this.lastAutocompleteQuery_ = '';
+ this.searchBox_.autocompleteList.suggestions = [];
+
+ // If the entry is the search item or no entry is selected, just change to
+ // the search result.
+ if (!selectedItem || selectedItem.isHeaderItem) {
+ const query = selectedItem ? selectedItem.searchQuery :
+ this.searchBox_.inputElement.value;
+ this.search_(query);
+ return;
+ }
+
+ // Clear the search box if an item except for the search item is
+ // selected. Eventually the following directory change clears the search
+ // box, but if the selected item is located just under /drive/other, the
+ // current directory will not changed. For handling the case, and for
+ // improving response time, clear the text manually here.
+ this.clear();
+
+ // If the entry is a directory, just change the directory.
+ const entry = selectedItem.entry;
+ if (entry.isDirectory) {
+ this.directoryModel_.changeDirectoryEntry(entry);
+ return;
+ }
+
+ // Change the current directory to the directory that contains the
+ // selected file. Note that this is necessary for an image or a video,
+ // which should be opened in the gallery mode, as the gallery mode
+ // requires the entry to be in the current directory model. For
+ // consistency, the current directory is always changed regardless of
+ // the file type.
+ entry.getParent(parentEntry => {
+ // Check if the parent entry points /drive/other or not.
+ // If so it just opens the file.
+ const locationInfo = this.volumeManager_.getLocationInfo(parentEntry);
+ if (!locationInfo ||
+ (locationInfo.isRootEntry &&
+ locationInfo.rootType ===
+ VolumeManagerCommon.RootType.DRIVE_OTHER)) {
+ this.taskController_.executeEntryTask(entry);
+ return;
+ }
+ // If the parent entry can be /drive/other.
+ this.directoryModel_.changeDirectoryEntry(parentEntry, () => {
+ this.directoryModel_.selectEntry(entry);
+ this.taskController_.executeEntryTask(entry);
+ });
+ });
+ }
+
+ /**
+ * Search files and update the list with the search result.
+ * @param {string} searchString String to be searched with.
+ * @private
+ */
+ search_(searchString) {
+ const onSearchRescan = function() {
+ // If the current location is somewhere in Drive, all files in Drive can
+ // be listed as search results regardless of current location.
+ // In this case, showing current location is confusing, so use the Drive
+ // root "My Drive" as the current location.
+ if (this.isOnDrive_) {
+ const locationInfo = this.currentLocationInfo_;
+ const rootEntry = locationInfo.volumeInfo.displayRoot;
+ if (rootEntry) {
+ this.locationLine_.show(rootEntry);
+ }
+ }
+ };
+
+ const onClearSearch = function() {
+ this.locationLine_.show(this.directoryModel_.getCurrentDirEntry());
+ };
+
+ this.directoryModel_.search(
+ searchString, onSearchRescan.bind(this), onClearSearch.bind(this));
+ }
+}