Index: ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js |
diff --git a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js b/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js |
deleted file mode 100644 |
index 415cf93f5c40da1129ea0f86c1c7099d2acf0195..0000000000000000000000000000000000000000 |
--- a/ui/file_manager/file_manager/foreground/js/folder_shortcuts_data_model.js |
+++ /dev/null |
@@ -1,527 +0,0 @@ |
-// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-/** |
- * The drive mount path used in the storage. It must be '/drive'. |
- * @type {string} |
- */ |
-var STORED_DRIVE_MOUNT_PATH = '/drive'; |
- |
-/** |
- * Model for the folder shortcuts. This object is cr.ui.ArrayDataModel-like |
- * object with additional methods for the folder shortcut feature. |
- * This uses chrome.storage as backend. Items are always sorted by URL. |
- * |
- * @param {VolumeManagerWrapper} volumeManager Volume manager instance. |
- * @constructor |
- * @extends {cr.EventTarget} |
- */ |
-function FolderShortcutsDataModel(volumeManager) { |
- this.volumeManager_ = volumeManager; |
- this.array_ = []; |
- this.pendingPaths_ = {}; // Hash map for easier deleting. |
- this.unresolvablePaths_ = {}; |
- this.lastDriveRootURL_ = null; |
- |
- // Queue to serialize resolving entries. |
- this.queue_ = new AsyncUtil.Queue(); |
- this.queue_.run( |
- this.volumeManager_.ensureInitialized.bind(this.volumeManager_)); |
- |
- // Load the shortcuts. Runs within the queue. |
- this.load_(); |
- |
- // Listening for changes in the storage. |
- chrome.storage.onChanged.addListener(function(changes, namespace) { |
- if (!(FolderShortcutsDataModel.NAME in changes) || namespace !== 'sync') |
- return; |
- this.reload_(); // Runs within the queue. |
- }.bind(this)); |
- |
- // If the volume info list is changed, then shortcuts have to be reloaded. |
- this.volumeManager_.volumeInfoList.addEventListener( |
- 'permuted', this.reload_.bind(this)); |
- |
- // If the drive status has changed, then shortcuts have to be re-resolved. |
- this.volumeManager_.addEventListener( |
- 'drive-connection-changed', this.reload_.bind(this)); |
-} |
- |
-/** |
- * Key name in chrome.storage. The array are stored with this name. |
- * @type {string} |
- * @const |
- */ |
-FolderShortcutsDataModel.NAME = 'folder-shortcuts-list'; |
- |
-FolderShortcutsDataModel.prototype = { |
- __proto__: cr.EventTarget.prototype, |
- |
- /** |
- * @return {number} Number of elements in the array. |
- */ |
- get length() { |
- return this.array_.length; |
- }, |
- |
- /** |
- * Remembers the Drive volume's root URL used for conversions between virtual |
- * paths and URLs. |
- * @private |
- */ |
- rememberLastDriveURL_: function() { |
- if (this.lastDriveRootURL_) |
- return; |
- var volumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo( |
- VolumeManagerCommon.VolumeType.DRIVE); |
- if (volumeInfo) |
- this.lastDriveRootURL_ = volumeInfo.fileSystem.root.toURL(); |
- }, |
- |
- /** |
- * Resolves Entries from a list of stored virtual paths. Runs within a queue. |
- * @param {Array.<string>} list List of virtual paths. |
- * @private |
- */ |
- processEntries_: function(list) { |
- this.queue_.run(function(callback) { |
- this.pendingPaths_ = {}; |
- this.unresolvablePaths_ = {}; |
- list.forEach(function(path) { |
- this.pendingPaths_[path] = true; |
- }, this); |
- callback(); |
- }.bind(this)); |
- |
- this.queue_.run(function(queueCallback) { |
- var volumeInfo = this.volumeManager_.getCurrentProfileVolumeInfo( |
- VolumeManagerCommon.VolumeType.DRIVE); |
- var changed = false; |
- var resolvedURLs = {}; |
- this.rememberLastDriveURL_(); // Required for conversions. |
- |
- var onResolveSuccess = function(path, entry) { |
- if (path in this.pendingPaths_) |
- delete this.pendingPaths_[path]; |
- if (path in this.unresolvablePaths_) { |
- changed = true; |
- delete this.unresolvablePaths_[path]; |
- } |
- if (!this.exists(entry)) { |
- changed = true; |
- this.addInternal_(entry); |
- } |
- resolvedURLs[entry.toURL()] = true; |
- }.bind(this); |
- |
- var onResolveFailure = function(path, url) { |
- if (path in this.pendingPaths_) |
- delete this.pendingPaths_[path]; |
- var existingIndex = this.getIndexByURL_(url); |
- if (existingIndex !== -1) { |
- changed = true; |
- this.removeInternal_(this.item(existingIndex)); |
- } |
- // Remove the shortcut on error, only if Drive is fully online. |
- // Only then we can be sure, that the error means that the directory |
- // does not exist anymore. |
- if (!volumeInfo || |
- this.volumeManager_.getDriveConnectionState().type !== |
- VolumeManagerCommon.DriveConnectionType.ONLINE) { |
- if (!this.unresolvablePaths_[path]) { |
- changed = true; |
- this.unresolvablePaths_[path] = true; |
- } |
- } |
- // Not adding to the model nor to the |unresolvablePaths_| means |
- // that it will be removed from the storage permanently after the |
- // next call to save_(). |
- }.bind(this); |
- |
- // Resolve the items all at once, in parallel. |
- var group = new AsyncUtil.Group(); |
- list.forEach(function(path) { |
- group.add(function(path, callback) { |
- var url = |
- this.lastDriveRootURL_ && this.convertStoredPathToUrl_(path); |
- if (url && volumeInfo) { |
- webkitResolveLocalFileSystemURL( |
- url, |
- function(entry) { |
- onResolveSuccess(path, entry); |
- callback(); |
- }, |
- function() { |
- onResolveFailure(path, url); |
- callback(); |
- }); |
- } else { |
- onResolveFailure(path, url); |
- callback(); |
- } |
- }.bind(this, path)); |
- }, this); |
- |
- // Save the model after finishing. |
- group.run(function() { |
- // Remove all of those old entries, which were resolved by this method. |
- var index = 0; |
- while (index < this.length) { |
- var entry = this.item(index); |
- if (!resolvedURLs[entry.toURL()]) { |
- this.removeInternal_(entry); |
- changed = true; |
- } else { |
- index++; |
- } |
- } |
- // If something changed, then save. |
- if (changed) |
- this.save_(); |
- queueCallback(); |
- }.bind(this)); |
- }.bind(this)); |
- }, |
- |
- /** |
- * Initializes the model and loads the shortcuts. |
- * @private |
- */ |
- load_: function() { |
- this.queue_.run(function(callback) { |
- chrome.storage.sync.get(FolderShortcutsDataModel.NAME, function(value) { |
- var shortcutPaths = value[FolderShortcutsDataModel.NAME] || []; |
- |
- // Record metrics. |
- metrics.recordSmallCount('FolderShortcut.Count', shortcutPaths.length); |
- |
- // Resolve and add the entries to the model. |
- this.processEntries_(shortcutPaths); // Runs within a queue. |
- callback(); |
- }.bind(this)); |
- }.bind(this)); |
- }, |
- |
- /** |
- * Reloads the model and loads the shortcuts. |
- * @private |
- */ |
- reload_: function(ev) { |
- var shortcutPaths; |
- this.queue_.run(function(callback) { |
- chrome.storage.sync.get(FolderShortcutsDataModel.NAME, function(value) { |
- var shortcutPaths = value[FolderShortcutsDataModel.NAME] || []; |
- this.processEntries_(shortcutPaths); // Runs within a queue. |
- callback(); |
- }.bind(this)); |
- }.bind(this)); |
- }, |
- |
- /** |
- * Returns the entries in the given range as a new array instance. The |
- * arguments and return value are compatible with Array.slice(). |
- * |
- * @param {number} begin Where to start the selection. |
- * @param {number=} opt_end Where to end the selection. |
- * @return {Array.<Entry>} Entries in the selected range. |
- */ |
- slice: function(begin, opt_end) { |
- return this.array_.slice(begin, opt_end); |
- }, |
- |
- /** |
- * @param {number} index Index of the element to be retrieved. |
- * @return {Entry} The value of the |index|-th element. |
- */ |
- item: function(index) { |
- return this.array_[index]; |
- }, |
- |
- /** |
- * @param {string} value URL of the entry to be found. |
- * @return {number} Index of the element with the specified |value|. |
- * @private |
- */ |
- getIndexByURL_: function(value) { |
- for (var i = 0; i < this.length; i++) { |
- // Same item check: must be exact match. |
- if (this.array_[i].toURL() === value) |
- return i; |
- } |
- return -1; |
- }, |
- |
- /** |
- * @param {Entry} value Value of the element to be retrieved. |
- * @return {number} Index of the element with the specified |value|. |
- */ |
- getIndex: function(value) { |
- for (var i = 0; i < this.length; i++) { |
- // Same item check: must be exact match. |
- if (util.isSameEntry(this.array_[i], value)) |
- return i; |
- } |
- return -1; |
- }, |
- |
- /** |
- * Compares 2 entries and returns a number indicating one entry comes before |
- * or after or is the same as the other entry in sort order. |
- * |
- * @param {Entry} a First entry. |
- * @param {Entry} b Second entry. |
- * @return {number} Returns -1, if |a| < |b|. Returns 0, if |a| === |b|. |
- * Otherwise, returns 1. |
- */ |
- compare: function(a, b) { |
- return util.comparePath(a, b); |
- }, |
- |
- /** |
- * Adds the given item to the array. If there were already same item in the |
- * list, return the index of the existing item without adding a duplicate |
- * item. |
- * |
- * @param {Entry} value Value to be added into the array. |
- * @return {number} Index in the list which the element added to. |
- */ |
- add: function(value) { |
- var result = this.addInternal_(value); |
- metrics.recordUserAction('FolderShortcut.Add'); |
- this.save_(); |
- return result; |
- }, |
- |
- /** |
- * Adds the given item to the array. If there were already same item in the |
- * list, return the index of the existing item without adding a duplicate |
- * item. |
- * |
- * @param {Entry} value Value to be added into the array. |
- * @return {number} Index in the list which the element added to. |
- * @private |
- */ |
- addInternal_: function(value) { |
- this.rememberLastDriveURL_(); // Required for saving. |
- |
- var oldArray = this.array_.slice(0); // Shallow copy. |
- var addedIndex = -1; |
- for (var i = 0; i < this.length; i++) { |
- // Same item check: must be exact match. |
- if (util.isSameEntry(this.array_[i], value)) |
- return i; |
- |
- // Since the array is sorted, new item will be added just before the first |
- // larger item. |
- if (this.compare(this.array_[i], value) >= 0) { |
- this.array_.splice(i, 0, value); |
- addedIndex = i; |
- break; |
- } |
- } |
- // If value is not added yet, add it at the last. |
- if (addedIndex == -1) { |
- this.array_.push(value); |
- addedIndex = this.length; |
- } |
- |
- this.firePermutedEvent_( |
- this.calculatePermutation_(oldArray, this.array_)); |
- return addedIndex; |
- }, |
- |
- /** |
- * Removes the given item from the array. |
- * @param {Entry} value Value to be removed from the array. |
- * @return {number} Index in the list which the element removed from. |
- */ |
- remove: function(value) { |
- var result = this.removeInternal_(value); |
- if (result !== -1) { |
- this.save_(); |
- metrics.recordUserAction('FolderShortcut.Remove'); |
- } |
- return result; |
- }, |
- |
- /** |
- * Removes the given item from the array. |
- * |
- * @param {Entry} value Value to be removed from the array. |
- * @return {number} Index in the list which the element removed from. |
- * @private |
- */ |
- removeInternal_: function(value) { |
- var removedIndex = -1; |
- var oldArray = this.array_.slice(0); // Shallow copy. |
- for (var i = 0; i < this.length; i++) { |
- // Same item check: must be exact match. |
- if (util.isSameEntry(this.array_[i], value)) { |
- this.array_.splice(i, 1); |
- removedIndex = i; |
- break; |
- } |
- } |
- |
- if (removedIndex !== -1) { |
- this.firePermutedEvent_( |
- this.calculatePermutation_(oldArray, this.array_)); |
- return removedIndex; |
- } |
- |
- // No item is removed. |
- return -1; |
- }, |
- |
- /** |
- * @param {Entry} entry Entry to be checked. |
- * @return {boolean} True if the given |entry| exists in the array. False |
- * otherwise. |
- */ |
- exists: function(entry) { |
- var index = this.getIndex(entry); |
- return (index >= 0); |
- }, |
- |
- /** |
- * Saves the current array to chrome.storage. |
- * @private |
- */ |
- save_: function() { |
- this.rememberLastDriveURL_(); |
- if (!this.lastDriveRootURL_) |
- return; |
- |
- // TODO(mtomasz): Migrate to URL. |
- var paths = this.array_. |
- map(function(entry) { return entry.toURL(); }). |
- map(this.convertUrlToStoredPath_.bind(this)). |
- concat(Object.keys(this.pendingPaths_)). |
- concat(Object.keys(this.unresolvablePaths_)); |
- |
- var prefs = {}; |
- prefs[FolderShortcutsDataModel.NAME] = paths; |
- chrome.storage.sync.set(prefs, function() {}); |
- }, |
- |
- /** |
- * Creates a permutation array for 'permuted' event, which is compatible with |
- * a permutation array used in cr/ui/array_data_model.js. |
- * |
- * @param {Array.<Entry>} oldArray Previous array before changing. |
- * @param {Array.<Entry>} newArray New array after changing. |
- * @return {Array.<number>} Created permutation array. |
- * @private |
- */ |
- calculatePermutation_: function(oldArray, newArray) { |
- var oldIndex = 0; // Index of oldArray. |
- var newIndex = 0; // Index of newArray. |
- |
- // Note that both new and old arrays are sorted. |
- var permutation = []; |
- for (; oldIndex < oldArray.length; oldIndex++) { |
- if (newIndex >= newArray.length) { |
- // oldArray[oldIndex] is deleted, which is not in the new array. |
- permutation[oldIndex] = -1; |
- continue; |
- } |
- |
- while (newIndex < newArray.length) { |
- // Unchanged item, which exists in both new and old array. But the |
- // index may be changed. |
- if (util.isSameEntry(oldArray[oldIndex], newArray[newIndex])) { |
- permutation[oldIndex] = newIndex; |
- newIndex++; |
- break; |
- } |
- |
- // oldArray[oldIndex] is deleted, which is not in the new array. |
- if (this.compare(oldArray[oldIndex], newArray[newIndex]) < 0) { |
- permutation[oldIndex] = -1; |
- break; |
- } |
- |
- // In the case of this.compare(oldArray[oldIndex]) > 0: |
- // newArray[newIndex] is added, which is not in the old array. |
- newIndex++; |
- } |
- } |
- return permutation; |
- }, |
- |
- /** |
- * Fires a 'permuted' event, which is compatible with cr.ui.ArrayDataModel. |
- * @param {Array.<number>} permutation Permutation array. |
- */ |
- firePermutedEvent_: function(permutation) { |
- var permutedEvent = new Event('permuted'); |
- permutedEvent.newLength = this.length; |
- permutedEvent.permutation = permutation; |
- this.dispatchEvent(permutedEvent); |
- |
- // Note: This model only fires 'permuted' event, because: |
- // 1) 'change' event is not necessary to fire since it is covered by |
- // 'permuted' event. |
- // 2) 'splice' and 'sorted' events are not implemented. These events are |
- // not used in NavigationListModel. We have to implement them when |
- // necessary. |
- }, |
- |
- /** |
- * Called externally when one of the items is not found on the filesystem. |
- * @param {Entry} entry The entry which is not found. |
- */ |
- onItemNotFoundError: function(entry) { |
- // If Drive is online, then delete the shortcut permanently. Otherwise, |
- // delete from model and add to |unresolvablePaths_|. |
- if (this.volumeManager_.getDriveConnectionState().type !== |
- VolumeManagerCommon.DriveConnectionType.ONLINE) { |
- var path = this.convertUrlToStoredPath_(entry.toURL()); |
- // TODO(mtomasz): Add support for multi-profile. |
- this.unresolvablePaths_[path] = true; |
- } |
- this.removeInternal_(entry); |
- this.save_(); |
- }, |
- |
- /** |
- * Converts the given "stored path" to the URL. |
- * |
- * This conversion is necessary because the shortcuts are not stored with |
- * stored-formatted mount paths for compatibility. See http://crbug.com/336155 |
- * for detail. |
- * |
- * @param {string} path Path in Drive with the stored drive mount path. |
- * @return {?string} URL of the given path. |
- * @private |
- */ |
- convertStoredPathToUrl_: function(path) { |
- if (path.indexOf(STORED_DRIVE_MOUNT_PATH + '/') !== 0) { |
- console.warn(path + ' is neither a drive mount path nor a stored path.'); |
- return null; |
- } |
- return this.lastDriveRootURL_ + encodeURIComponent( |
- path.substr(STORED_DRIVE_MOUNT_PATH.length)); |
- }, |
- |
- /** |
- * Converts the URL to the stored-formatted path. |
- * |
- * See the comment of convertStoredPathToUrl_() for further information. |
- * |
- * @param {string} url URL of the directory in Drive. |
- * @return {?string} Path with the stored drive mount path. |
- * @private |
- */ |
- convertUrlToStoredPath_: function(url) { |
- // Root URLs contain a trailing slash. |
- if (url.indexOf(this.lastDriveRootURL_) !== 0) { |
- console.warn(url + ' is not a drive URL.'); |
- return null; |
- } |
- |
- return STORED_DRIVE_MOUNT_PATH + '/' + decodeURIComponent( |
- url.substr(this.lastDriveRootURL_.length)); |
- }, |
-}; |