| 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));
|
| - },
|
| -};
|
|
|