diff options
author | fukino@chromium.org <fukino@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-07 02:29:28 +0000 |
---|---|---|
committer | fukino@chromium.org <fukino@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-07 02:29:28 +0000 |
commit | 277bb8c5221f3125730b671083f7f254fb9aea66 (patch) | |
tree | 81014907bb8b3f67b3dddefdc8b671714ad082e4 /ui | |
parent | 252455d3a7f53610b204efc9066a51424f03141c (diff) | |
download | chromium_src-277bb8c5221f3125730b671083f7f254fb9aea66.zip chromium_src-277bb8c5221f3125730b671083f7f254fb9aea66.tar.gz chromium_src-277bb8c5221f3125730b671083f7f254fb9aea66.tar.bz2 |
Merge navigation list and directory tree.
This CL merges navigation list (the very left pane) and directory tree (middle pane).
In the conbined tree, the first-level children are VolumeItem or ShortcutItem, which correspond to NavigationModelItem.
Only Drive volume has children and the Drive volume. They are DirectoryItem and the behavior is similar to previous directory tree.
BUG=390848,397222
TEST=run browser_tests
Review URL: https://codereview.chromium.org/441233002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287933 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
8 files changed, 548 insertions, 586 deletions
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css index 1ab53cc..1275c12 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager.css @@ -147,7 +147,7 @@ a:focus { min-width: 100px; overflow: hidden; position: relative; - width: 150px; + width: 190px; } .dialog-navigation-list-header { @@ -269,7 +269,6 @@ div.splitter { } #directory-tree { - -webkit-border-end: 1px solid rgba(20, 20, 22, 0.1); bottom: 0; flex: none; left: 0; @@ -278,7 +277,7 @@ div.splitter { padding-bottom: 0; /* For the preview panel. Will be overridden by JS. */ position: absolute; right: 0; - top: 47px; + top: 0; } #directory-tree .tree-row { @@ -357,7 +356,16 @@ div.splitter { color: white; } -#navigation-list .root-item > div.root-eject { +/* Make top-level items thicker and their expand-icno invisible */ +#directory-tree > .tree-item > .tree-row { + line-height: 40px; +} + +#directory-tree > .tree-item > .tree-row > .expand-icon { + visibility: hidden; +} + +#directory-tree .tree-row > div.root-eject { background: -webkit-image-set( url('../images/files/ui/eject.png') 1x, url('../images/files/ui/2x/eject.png') 2x) no-repeat center; @@ -370,7 +378,7 @@ div.splitter { width: 20px; } -#navigation-list:focus .root-item[selected] > div.root-eject { +#directory-tree:focus .tree-row[selected] > div.root-eject { background: -webkit-image-set( url('../images/files/ui/eject_white.png') 1x, url('../images/files/ui/2x/eject_white.png') 2x) no-repeat center; diff --git a/ui/file_manager/file_manager/foreground/js/directory_tree.js b/ui/file_manager/file_manager/foreground/js/directory_tree.js index a689242..aa87168 100644 --- a/ui/file_manager/file_manager/foreground/js/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/directory_tree.js @@ -85,6 +85,14 @@ DirectoryItemTreeBaseMethods.searchAndSelectByEntry = function(entry) { Object.freeze(DirectoryItemTreeBaseMethods); +var TREE_ITEM_INNTER_HTML = + '<div class="tree-row">' + + ' <span class="expand-icon"></span>' + + ' <span class="icon"></span>' + + ' <span class="label entry-name"></span>' + + '</div>' + + '<div class="tree-children"></div>'; + //////////////////////////////////////////////////////////////////////////////// // DirectoryItem @@ -170,14 +178,7 @@ DirectoryItem.prototype.searchAndSelectByEntry = function(entry) { */ DirectoryItem.prototype.decorate = function( label, dirEntry, parentDirItem, tree) { - this.innerHTML = - '<div class="tree-row">' + - ' <span class="expand-icon"></span>' + - ' <span class="icon"></span>' + - ' <span class="label entry-name"></span>' + - '</div>' + - '<div class="tree-children"></div>'; - + this.innerHTML = TREE_ITEM_INNTER_HTML; this.parentTree_ = tree; this.directoryModel_ = tree.directoryModel; this.parent_ = parentDirItem; @@ -339,11 +340,11 @@ DirectoryItem.prototype.updateItemByEntry = function(changedDirectoryEntry) { */ DirectoryItem.prototype.updateSharedStatusIcon = function() { var icon = this.querySelector('.icon'); - this.parentTree_.metadataCache.getOne( - this.dirEntry_, + this.parentTree_.metadataCache.getLatest( + [this.dirEntry_], 'drive', function(metadata) { - icon.classList.toggle('shared', metadata && metadata.shared); + icon.classList.toggle('shared', metadata[0] && metadata[0].shared); }); }; @@ -394,6 +395,378 @@ DirectoryItem.prototype.setContextMenu = function(menu) { cr.ui.contextMenuHandler.setContextMenu(this, menu); }; +DirectoryItem.prototype.activate = function() { + this.parentTree_.directoryModel.activateDirectoryEntry(this.entry); +}; + +//////////////////////////////////////////////////////////////////////////////// +// VolumeItem + +/** + * A TreeItem which represents a volume. Volume items are displayed as + * top-level children of DirectoryTree. + * + * @param {DirectoryEntry} dirEntry DirectoryEntry of this item. + * @param {NavigationModelItem} modelItem NavigationModelItem of this volume. + * @param {DirectoryTree} tree Current tree, which contains this item. + * @extends {cr.ui.TreeItem} + * @constructor + */ +function VolumeItem(entry, modelItem, tree) { + var item = new cr.ui.TreeItem(); + item.__proto__ = VolumeItem.prototype; + item.decorate(entry, modelItem, tree); + return item; +} + +VolumeItem.prototype = { + __proto__: cr.ui.TreeItem.prototype, + get entry() { + return this.dirEntry_; + }, + get modelItem() { + return this.modelItem_; + }, + get volumeInfo() { + return this.volumeInfo_; + }, + get labelElement() { + return this.firstElementChild.querySelector('.label'); + }, + // Overrides the property 'expanded' to prevent volume items from shrinking. + get expanded() { + return Object.getOwnPropertyDescriptor( + cr.ui.TreeItem.prototype, 'expanded').get.call(this); + }, + set expanded(b) { + if (!b) + return; + Object.getOwnPropertyDescriptor( + cr.ui.TreeItem.prototype, 'expanded').set.call(this, b); + } +}; + +/** + * Calls DirectoryItemTreeBaseMethods.updateSubElementsFromList(). + * + * @param {DirectoryEntry|Object} entry The entry to be searched for. Can be + * a fake. + * @return {boolean} True if the parent item is found. + */ +VolumeItem.prototype.searchAndSelectByEntry = function(entry) { + return DirectoryItemTreeBaseMethods.searchAndSelectByEntry.call(this, entry); +}; + +/** + * Decorates this element. + * @param {DirectoryEntry} dirEntry DirectoryEntry of this item. + * @param {NavigationModelItem} modelItem NavigationModelItem of this volume. + * @param {DirectoryTree} tree Current tree, which contains this item. + */ +VolumeItem.prototype.decorate = function(entry, modelItem, tree) { + this.innerHTML = TREE_ITEM_INNTER_HTML; + this.parentTree_ = tree; + this.dirEntry_ = entry; + this.modelItem_ = modelItem; + this.volumeInfo_ = modelItem.volumeInfo; + this.label = modelItem.volumeInfo.label; + + this.setupIcon_(this.querySelector('.icon'), this.volumeInfo); + this.setupEjectButton_(this.rowElement); + if (tree.contextMenuForRootItems) + this.setContextMenu(tree.contextMenuForRootItems); + + this.updateSubDirectories(false /* recursive */); +}; + +/** + * Invoked when the tree item is clicked. + * + * @param {Event} e Click event. + * @override + */ +VolumeItem.prototype.handleClick = function(e) { + cr.ui.TreeItem.prototype.handleClick.call(this, e); + + // Resets file selection when a volume is clicked. + this.parentTree_.directoryModel.clearSelection(); + + // If the Drive volume is clicked, select one of the children instead of this + // item itself. + if (this.isDrive()) + this.searchAndSelectByEntry(this.entry); +}; + +/** + * Retrieves the latest subdirectories and update them on the tree. + * @param {boolean} recursive True if the update is recursively. + */ +VolumeItem.prototype.updateSubDirectories = function(recursive) { + // Drive volume has children including fake entries (offline, recent, etc...). + if (this.isDrive()) { + var entries = [this.entry]; + if (this.parentTree_.fakeEntriesVisible_) { + for (var key in this.volumeInfo.fakeEntries) + entries.push(this.volumeInfo.fakeEntries[key]); + } + entries.sort(function(a, b) { return a.toURL() < b.toURL(); }); + + for (var i = 0; i < entries.length; i++) { + var item = new DirectoryItem( + util.getEntryLabel(this.parentTree_.volumeManager_, entries[i]), + entries[i], this, this.parentTree_); + this.add(item); + item.updateSubDirectories(false); + } + this.expanded = true; + } +}; + +/** + * Searches for the changed directory in the current subtree, and if it is found + * then updates it. + * + * @param {DirectoryEntry} changedDirectoryEntry The entry ot the changed + * directory. + */ +VolumeItem.prototype.updateItemByEntry = function(changedDirectoryEntry) { + if (this.isDrive()) + this.items[0].updateItemByEntry(changedDirectoryEntry); +}; + +/** + * Select the item corresponding to the given entry. + * @param {DirectoryEntry|Object} entry The directory entry to be selected. Can + * be a fake. + */ +VolumeItem.prototype.selectByEntry = function(entry) { + // If this volume is drive, find the item to be selected amang children. + if (this.isDrive()) { + this.searchAndSelectByEntry(entry); + return; + } + if (util.isSameEntry(entry, this.entry)) + this.selected = true; +}; + +/** + * Sets the context menu for volume items. + * @param {cr.ui.Menu} menu Menu to be set. + */ +VolumeItem.prototype.setContextMenu = function(menu) { + if (this.isRemovable_()) + cr.ui.contextMenuHandler.setContextMenu(this, menu); +}; + +/** + * Change current entry to this volume's root directory. + */ +VolumeItem.prototype.activate = function() { + var directoryModel = this.parentTree_.directoryModel; + var onEntryResolved = function(entry) { + // Changes directory to the model item's root directory if needed. + if (!util.isSameEntry(directoryModel.getCurrentDirEntry(), entry)) { + metrics.recordUserAction('FolderShortcut.Navigate'); + directoryModel.changeDirectoryEntry(entry); + } + }.bind(this); + + this.volumeInfo.resolveDisplayRoot( + onEntryResolved, + function() { + // Error, the display root is not available. It may happen on Drive. + this.parentTree_.dataModel.onItemNotFoundError(this.modelItem); + }.bind(this)) +}; + +/** + * @return {boolean} True if this is Drive volume. + */ +VolumeItem.prototype.isDrive = function() { + return this.volumeInfo.volumeType === VolumeManagerCommon.VolumeType.DRIVE; +}; + +/** + * @return {boolean} True if this volume can be removed by user operation. + * @private + */ +VolumeItem.prototype.isRemovable_ = function() { + var volumeType = this.volumeInfo.volumeType; + return volumeType === VolumeManagerCommon.VolumeType.ARCHIVE || + volumeType === VolumeManagerCommon.VolumeType.REMOVABLE || + volumeType === VolumeManagerCommon.VolumeType.PROVIDED; +}; + +/** + * Set up icon of this volume item. + * @param {HTMLElement} icon Icon element to be setup. + * @param {VolumeInfo} volumeInfo VolumeInfo determines the icon type. + * @private + */ +VolumeItem.prototype.setupIcon_ = function(icon, volumeInfo) { + icon.classList.add('volume-icon'); + if (volumeInfo.volumeType === 'provided') { + var backgroundImage = '-webkit-image-set(' + + 'url(chrome://extension-icon/' + volumeInfo.extensionId + + '/24/1) 1x, ' + + 'url(chrome://extension-icon/' + volumeInfo.extensionId + + '/48/1) 2x);'; + // The icon div is not yet added to DOM, therefore it is impossible to + // use style.backgroundImage. + icon.setAttribute( + 'style', 'background-image: ' + backgroundImage); + } + icon.setAttribute('volume-type-icon', volumeInfo.volumeType); + icon.setAttribute('volume-subtype', volumeInfo.deviceType); +}; + +/** + * Set up eject button if needed. + * @param {HTMLElement} rowElement The parent element for eject button. + * @private + */ +VolumeItem.prototype.setupEjectButton_ = function(rowElement) { + if (this.isRemovable_()) { + var ejectButton = cr.doc.createElement('div'); + // Block other mouse handlers. + ejectButton.addEventListener( + 'mouseup', function(event) { event.stopPropagation() }); + ejectButton.addEventListener( + 'mousedown', function(event) { event.stopPropagation() }); + ejectButton.className = 'root-eject'; + ejectButton.addEventListener('click', function(event) { + event.stopPropagation(); + var unmountCommand = cr.doc.querySelector('command#unmount'); + // Let's make sure 'canExecute' state of the command is properly set for + // the root before executing it. + unmountCommand.canExecuteChange(this); + unmountCommand.execute(this); + }.bind(this)); + rowElement.appendChild(ejectButton); + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// ShortcutItem + +/** + * A TreeItem which represents a shortcut for Drive folder. + * Shortcut items are displayed as top-level children of DirectoryTree. + * + * @param {DirectoryEntry} dirEntry DirectoryEntry of this item. + * @param {NavigationModelItem} modelItem NavigationModelItem of this volume. + * @param {DirectoryTree} tree Current tree, which contains this item. + * @extends {cr.ui.TreeItem} + * @constructor + */ +function ShortcutItem(dirEntry, modelItem, tree) { + var item = new cr.ui.TreeItem(); + item.__proto__ = ShortcutItem.prototype; + item.decorate(dirEntry, modelItem, tree); + return item; +} + +ShortcutItem.prototype = { + __proto__: cr.ui.TreeItem.prototype, + get entry() { + return this.dirEntry_; + }, + get modelItem() { + return this.modelItem_; + }, + get labelElement() { + return this.firstElementChild.querySelector('.label'); + } +}; + +/** + * Finds a parent directory of the {@code entry} in {@code this}, and + * invokes the DirectoryItem.selectByEntry() of the found directory. + * + * @param {DirectoryEntry|Object} entry The entry to be searched for. Can be + * a fake. + * @return {boolean} True if the parent item is found. + */ +ShortcutItem.prototype.searchAndSelectByEntry = function(entry) { + // Always false as shortcuts have no children. + return false; +}; + +/** + * Decorates this element. + * @param {DirectoryEntry} dirEntry DirectoryEntry of this item. + * @param {NavigationModelItem} modelItem NavigationModelItem of this volume. + * @param {DirectoryTree} tree Current tree, which contains this item. + */ +ShortcutItem.prototype.decorate = function(dirEntry, modelItem, tree) { + this.innerHTML = TREE_ITEM_INNTER_HTML; + this.parentTree_ = tree; + this.label = dirEntry.name; + this.dirEntry_ = dirEntry; + this.modelItem_ = modelItem; + + var icon = this.querySelector('.icon'); + icon.classList.add('volume-icon'); + icon.setAttribute('volume-type-icon', VolumeManagerCommon.VolumeType.DRIVE); + + if (tree.contextMenuForRootItems) + this.setContextMenu(tree.contextMenuForRootItems); +}; + +/** + * Invoked when the tree item is clicked. + * + * @param {Event} e Click event. + * @override + */ +ShortcutItem.prototype.handleClick = function(e) { + cr.ui.TreeItem.prototype.handleClick.call(this, e); + this.parentTree_.directoryModel.clearSelection(); +}; + +/** + * Select the item corresponding to the given entry. + * @param {DirectoryEntry} entry The directory entry to be selected. + */ +ShortcutItem.prototype.selectByEntry = function(entry) { + if (util.isSameEntry(entry, this.entry)) + this.selected = true; +}; + +/** + * Sets the context menu for shortcut items. + * @param {cr.ui.Menu} menu Menu to be set. + */ +ShortcutItem.prototype.setContextMenu = function(menu) { + cr.ui.contextMenuHandler.setContextMenu(this, menu); +}; + +/** + * Change current entry to the entry corresponding to this shortcut. + */ +ShortcutItem.prototype.activate = function() { + var directoryModel = this.parentTree_.directoryModel; + var onEntryResolved = function(entry) { + // Changes directory to the model item's root directory if needed. + if (!util.isSameEntry(directoryModel.getCurrentDirEntry(), entry)) { + metrics.recordUserAction('FolderShortcut.Navigate'); + directoryModel.changeDirectoryEntry(entry); + } + }.bind(this); + + // For shortcuts we already have an Entry, but it has to be resolved again + // in case, it points to a non-existing directory. + webkitResolveLocalFileSystemURL( + this.entry.toURL(), + onEntryResolved, + function() { + // Error, the entry can't be re-resolved. It may happen for shortcuts + // which targets got removed after resolving the Entry during + // initialization. + this.parentTree_.dataModel.onItemNotFoundError(this.modelItem); + }.bind(this)); +}; + //////////////////////////////////////////////////////////////////////////////// // DirectoryTree @@ -464,9 +837,29 @@ DirectoryTree.prototype = { get metadataCache() { return this.metadataCache_; }, + + set dataModel(dataModel) { + if (!this.onListContentChangedBound_) + this.onListContentChangedBound_ = this.onListContentChanged_.bind(this); + + if (this.dataModel_) { + this.dataModel_.removeEventListener( + 'change', this.onListContentChangedBound_); + this.dataModel_.removeEventListener( + 'permuted', this.onListContentChangedBound_); + } + this.dataModel_ = dataModel; + dataModel.addEventListener('change', this.onListContentChangedBound_); + dataModel.addEventListener('permuted', this.onListContentChangedBound_); + }, + + get dataModel() { + return this.dataModel_; + } }; cr.defineProperty(DirectoryTree, 'contextMenuForSubitems', cr.PropertyKind.JS); +cr.defineProperty(DirectoryTree, 'contextMenuForRootItems', cr.PropertyKind.JS); /** * Calls DirectoryItemTreeBaseMethods.updateSubElementsFromList(). @@ -476,17 +869,75 @@ cr.defineProperty(DirectoryTree, 'contextMenuForSubitems', cr.PropertyKind.JS); * only immediate child directories without arrows. */ DirectoryTree.prototype.updateSubElementsFromList = function(recursive) { - DirectoryItemTreeBaseMethods.updateSubElementsFromList.call(this, recursive); + // First, current items which is not included in the models_[] should be + // removed. + for (var i = 0; i < this.items.length;) { + var found = false; + for (var j = 0; j < this.models_.length; j++) { + if (util.isSameEntry(this.items[i].entry, this.models_[j].entry)) { + found = true; + break; + } + } + if (!found) { + if (this.items[i].selected) + this.items[i].selected = false; + this.remove(this.items[i]); + } else { + i++; + } + } + + // Next, insert items which is in models_[] but not in current items. + var modelIndex = 0; + var itemIndex = 0; + while (modelIndex < this.models_.length) { + if (itemIndex < this.items.length && + util.isSameEntry(this.items[itemIndex].entry, + this.models_[modelIndex].entry)) { + if (recursive && this.items[itemIndex] instanceof VolumeItem) + this.items[itemIndex].updateSubDirectories(true); + } else { + var model = this.models_[modelIndex]; + if (model.modelItem.isVolume) { + this.addAt(new VolumeItem(model.entry, model.modelItem, this), + itemIndex); + } else { + this.addAt(new ShortcutItem(model.entry, model.modelItem, this), + itemIndex); + } + } + itemIndex++; + modelIndex++; + } + + if (itemIndex !== 0) + this.hasChildren = true; }; /** - * Calls DirectoryItemTreeBaseMethods.updateSubElementsFromList(). + * Finds a parent directory of the {@code entry} in {@code this}, and + * invokes the DirectoryItem.selectByEntry() of the found directory. * * @param {DirectoryEntry|Object} entry The entry to be searched for. Can be * a fake. * @return {boolean} True if the parent item is found. */ DirectoryTree.prototype.searchAndSelectByEntry = function(entry) { + // If the |entry| is same as one of volumes or shortcuts, select it. + for (var i = 0; i < this.items.length; i++) { + // Skips the Drive root volume. For Drive entries, one of children of Drive + // root or shortcuts should be selected. + var item = this.items[i]; + if (item instanceof VolumeItem && item.isDrive()) + continue; + + if (util.isSameEntry(item.entry, entry)) { + item.selectByEntry(entry); + return true; + } + } + // Otherwise, search whole tree. return DirectoryItemTreeBaseMethods.searchAndSelectByEntry.call(this, entry); }; @@ -505,8 +956,7 @@ DirectoryTree.prototype.decorate = function( this.directoryModel_ = directoryModel; this.volumeManager_ = volumeManager; this.metadataCache_ = metadataCache; - this.entries_ = []; - this.currentVolumeInfo_ = null; + this.models_ = []; this.fileFilter_ = this.directoryModel_.getFileFilter(); this.fileFilter_.addEventListener('changed', @@ -518,7 +968,7 @@ DirectoryTree.prototype.decorate = function( // Add a handler for directory change. this.addEventListener('change', function() { if (this.selectedItem) - this.directoryModel_.activateDirectoryEntry(this.selectedItem.entry); + this.selectedItem.activate(); }.bind(this)); this.privateOnDirectoryChangedBound_ = @@ -543,12 +993,6 @@ DirectoryTree.prototype.decorate = function( * be a fake. */ DirectoryTree.prototype.selectByEntry = function(entry) { - // If the target directory is not in the tree, do nothing. - var locationInfo = this.volumeManager_.getLocationInfo(entry); - if (!locationInfo || !locationInfo.isDriveBased) - return; - - var volumeInfo = this.volumeManager_.getVolumeInfo(entry); if (this.selectedItem && util.isSameEntry(entry, this.selectedItem.entry)) return; @@ -557,6 +1001,7 @@ DirectoryTree.prototype.selectByEntry = function(entry) { this.updateSubDirectories(false /* recursive */); var currentSequence = ++this.sequence_; + var volumeInfo = this.volumeManager_.getVolumeInfo(entry); volumeInfo.resolveDisplayRoot(function() { if (this.sequence_ !== currentSequence) return; @@ -566,6 +1011,18 @@ DirectoryTree.prototype.selectByEntry = function(entry) { }; /** + * Select the volume or the shortcut corresponding to the given index. + * @param {number} index 0-based index of the target top-level item. + */ +DirectoryTree.prototype.selectByIndex = function(index) { + if (index < 0 || index >= this.items.length) + return false; + + this.items[index].selected = true; + return true; +}; + +/** * Retrieves the latest subdirectories and update them on the tree. * * @param {boolean} recursive True if the update is recursively. @@ -575,33 +1032,32 @@ DirectoryTree.prototype.selectByEntry = function(entry) { DirectoryTree.prototype.updateSubDirectories = function( recursive, opt_callback) { var callback = opt_callback || function() {}; - this.entries_ = []; - - var compareEntries = function(a, b) { - return a.toURL() < b.toURL(); - }; - // Add fakes (if any). - if (this.fakeEntriesVisible_) { - for (var key in this.currentVolumeInfo_.fakeEntries) { - this.entries_.push(this.currentVolumeInfo_.fakeEntries[key]); + // Resolves all root entries for model items. + var itemPromises = []; + for (var i = 0; i < this.dataModel.length; i++) { + if (this.dataModel.item(i).isVolume) { + // Volume's root entries need to be resolved. + itemPromises.push(new Promise(function(resolve, reject) { + var modelItem = this.dataModel.item(i); + modelItem.volumeInfo.resolveDisplayRoot(function(entry) { + resolve({entry: entry, modelItem: modelItem}); + }); + }.bind(this))); + } else { + // Shortcuts' root entries can be obtained immediately. + itemPromises.push( + Promise.resolve({entry: this.dataModel.item(i).entry, + modelItem: this.dataModel.item(i)})); } } - // If the display root is not available yet, then redraw anyway with what - // we have. However, concurrently try to resolve the display root and then - // redraw. - if (!this.currentVolumeInfo_.displayRoot) { - this.entries_.sort(compareEntries); + // Redraws this tree using resolved root entries and volume info. + Promise.all(itemPromises).then(function(results) { + this.models_ = results; this.redraw(recursive); - } - - this.currentVolumeInfo_.resolveDisplayRoot(function(displayRoot) { - this.entries_.push(this.currentVolumeInfo_.displayRoot); - this.entries_.sort(compareEntries); - this.redraw(recursive); // Redraw. callback(); - }.bind(this), callback /* Ignore errors. */); + }.bind(this)); }; /** @@ -634,13 +1090,10 @@ DirectoryTree.prototype.onDirectoryContentChanged_ = function(event) { if (event.eventType !== 'changed') return; - var locationInfo = this.volumeManager_.getLocationInfo(event.entry); - if (!locationInfo || !locationInfo.isDriveBased) - return; - - var myDriveItem = this.items[0]; - if (myDriveItem) - myDriveItem.updateItemByEntry(event.entry); + for (var i = 0; i < this.items.length; i++) { + if (this.items[i] instanceof VolumeItem) + this.items[i].updateItemByEntry(event.entry); + } }; /** @@ -649,18 +1102,24 @@ DirectoryTree.prototype.onDirectoryContentChanged_ = function(event) { * @private */ DirectoryTree.prototype.onCurrentDirectoryChanged_ = function(event) { - this.currentVolumeInfo_ = - this.volumeManager_.getVolumeInfo(event.newDirEntry); this.selectByEntry(event.newDirEntry); }; /** - * Sets the margin height for the transparent preview panel at the bottom. - * @param {number} margin Margin to be set in px. + * Invoked when the volume list or shortcut list is changed. + * @private */ -DirectoryTree.prototype.setBottomMarginForPanel = function(margin) { - this.style.paddingBottom = margin + 'px'; - this.scrollBar_.setBottomMarginForPanel(margin); +DirectoryTree.prototype.onListContentChanged_ = function() { + this.updateSubDirectories(false, function() { + // If no item is selected now, try to select the item corresponding to + // current directory because the current directory might have been populated + // in this tree in previous updateSubDirectories(). + if (!this.selectedItem) { + var currentDir = this.directoryModel_.getCurrentDirEntry(); + if (currentDir) + this.selectByEntry(currentDir); + } + }.bind(this)); }; /** diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js index b9c2499..8d097fb 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager.js @@ -74,8 +74,8 @@ FileManager.prototype = { get directoryModel() { return this.directoryModel_; }, - get navigationList() { - return this.navigationList_; + get directoryTree() { + return this.directoryTree_; }, get document() { return this.document_; @@ -419,7 +419,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; controller.attachDragSource(this.grid_); controller.attachFileListDropTarget(this.grid_); controller.attachTreeDropTarget(this.directoryTree_); - controller.attachNavigationListDropTarget(this.navigationList_, true); controller.attachCopyPasteHandlers(); controller.addEventListener('selection-copied', this.blinkSelection.bind(this)); @@ -465,7 +464,7 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; this.rootsContextMenu_ = this.dialogDom_.querySelector('#roots-context-menu'); cr.ui.Menu.decorate(this.rootsContextMenu_); - this.navigationList_.setContextMenu(this.rootsContextMenu_); + this.directoryTree_.contextMenuForRootItems = this.rootsContextMenu_; this.directoryTreeContextMenu_ = this.dialogDom_.querySelector('#directory-tree-context-menu'); @@ -870,8 +869,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; this.decorateSplitter( this.dialogDom_.querySelector('#navigation-list-splitter')); - this.decorateSplitter( - this.dialogDom_.querySelector('#middlebar-splitter')); this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); @@ -1038,7 +1035,7 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; // TODO(mtomasz, yoshiki): Create navigation list earlier, and here just // attach the directory model. - this.initNavigationList_(); + this.initDirectoryTree_(); this.table_.addEventListener('column-resize-end', this.updateStartupPrefs_.bind(this)); @@ -1077,45 +1074,22 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; /** * @private */ - FileManager.prototype.initNavigationList_ = function() { + FileManager.prototype.initDirectoryTree_ = function() { var fakeEntriesVisible = - this.dialogType != DialogType.SELECT_SAVEAS_FILE; + this.dialogType !== DialogType.SELECT_SAVEAS_FILE; this.directoryTree_ = this.dialogDom_.querySelector('#directory-tree'); DirectoryTree.decorate(this.directoryTree_, this.directoryModel_, this.volumeManager_, this.metadataCache_, fakeEntriesVisible); - - this.navigationList_ = this.dialogDom_.querySelector('#navigation-list'); - NavigationList.decorate(this.navigationList_, - this.volumeManager_, - this.directoryModel_); - this.navigationList_.fileManager = this; - this.navigationList_.dataModel = new NavigationListModel( + this.directoryTree_.dataModel = new NavigationListModel( this.volumeManager_, this.folderShortcutsModel_); }; /** * @private */ - FileManager.prototype.updateMiddleBarVisibility_ = function() { - var entry = this.directoryModel_.getCurrentDirEntry(); - if (!entry) - return; - - var driveVolume = this.volumeManager_.getVolumeInfo(entry); - var visible = driveVolume && !driveVolume.error && - driveVolume.volumeType === VolumeManagerCommon.VolumeType.DRIVE; - this.dialogDom_. - querySelector('.dialog-middlebar-contents').hidden = !visible; - this.dialogDom_.querySelector('#middlebar-splitter').hidden = !visible; - this.onResize_(); - }; - - /** - * @private - */ FileManager.prototype.updateStartupPrefs_ = function() { var sortStatus = this.directoryModel_.getFileList().sortStatus; var prefs = { @@ -1403,11 +1377,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; if (this.directoryTree_) this.directoryTree_.relayout(); - // TODO(mtomasz, yoshiki): Initialize navigation list earlier, before - // file system is available. - if (this.navigationList_) - this.navigationList_.redraw(); - this.previewPanel_.breadcrumbs.truncate(); }; @@ -1435,11 +1404,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; this.grid_.setBottomMarginForPanel(panelHeight); if (this.table_) this.table_.setBottomMarginForPanel(panelHeight); - - if (this.directoryTree_) { - this.directoryTree_.setBottomMarginForPanel(panelHeight); - this.ensureDirectoryTreeItemNotBehindPreviewPanel_(); - } }; /** @@ -2761,7 +2725,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; // Check if batch updates are already finished by onScanUpdated_(). if (!this.scanUpdatedAtLeastOnceOrCompleted_) { this.scanUpdatedAtLeastOnceOrCompleted_ = true; - this.updateMiddleBarVisibility_(); } this.scanInProgress_ = false; @@ -2790,7 +2753,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; if (!this.scanUpdatedAtLeastOnceOrCompleted_) { this.scanUpdatedAtLeastOnceOrCompleted_ = true; this.hideSpinnerLater_(); - this.updateMiddleBarVisibility_(); } // Update the UI. @@ -2827,7 +2789,6 @@ var BOTTOM_MARGIN_FOR_PREVIEW_PANEL_PX = 52; // Finish unfinished batch updates. if (!this.scanUpdatedAtLeastOnceOrCompleted_) { this.scanUpdatedAtLeastOnceOrCompleted_ = true; - this.updateMiddleBarVisibility_(); } this.scanInProgress_ = false; diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index 275fa95..ae735ee 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js @@ -41,30 +41,18 @@ var CommandUtil = {}; /** * Extracts entry on which command event was dispatched. * - * @param {DirectoryTree|DirectoryItem|NavigationList|HTMLLIElement|cr.ui.List} + * @param {DirectoryTree|DirectoryItem|HTMLLIElement|cr.ui.List} * element Directory to extract a path from. * @return {Entry} Entry of the found node. */ CommandUtil.getCommandEntry = function(element) { - if (element instanceof NavigationList) { - // element is a NavigationList. - /** @type {NavigationModelItem} */ - var item = element.selectedItem; - return element.selectedItem && - CommandUtil.getEntryFromNavigationModelItem_(item); - } else if (element instanceof NavigationListItem) { - // element is a subitem of NavigationList. - /** @type {NavigationList} */ - var navigationList = element.parentElement; - var index = navigationList.getIndexOfListItem(element); - /** @type {NavigationModelItem} */ - var item = (index != -1) ? navigationList.dataModel.item(index) : null; - return item && CommandUtil.getEntryFromNavigationModelItem_(item); - } else if (element instanceof DirectoryTree) { + if (element instanceof DirectoryTree) { // element is a DirectoryTree. - return element.selectedItem.entry; - } else if (element instanceof DirectoryItem) { - // element is a sub item in DirectoryTree. + return element.selectedItem ? element.selectedItem.entry : null; + } else if (element instanceof DirectoryItem || + element instanceof VolumeItem || + element instanceof ShortcutItem) { + // element are sub items in DirectoryTree. return element.entry; } else if (element instanceof cr.ui.List) { // element is a normal List (eg. the file list on the right panel). @@ -214,11 +202,11 @@ CommandUtil.defaultCommand = { CommandUtil.createVolumeSwitchCommand = function(index) { return { execute: function(event, fileManager) { - fileManager.navigationList.selectByIndex(index - 1); + fileManager.directoryTree.selectByIndex(index - 1); }, canExecute: function(event, fileManager) { event.canExecute = index > 0 && - index <= fileManager.navigationList.dataModel.length; + index <= fileManager.directoryTree.items.length; } }; }; @@ -834,8 +822,7 @@ CommandHandler.COMMANDS_['create-folder-shortcut'] = { var onlyOneFolderSelected = true; // Only on list, user can select multiple files. The command is enabled only // when a single file is selected. - if (event.target instanceof cr.ui.List && - !(event.target instanceof NavigationList)) { + if (event.target instanceof cr.ui.List) { var items = event.target.selectedItems; onlyOneFolderSelected = (items.length == 1 && items[0].isDirectory); } diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js index 1730bff..f3ec7a2 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js @@ -614,7 +614,7 @@ FileTransferController.prototype = { event.preventDefault(); // Required to prevent the cursor flicker. this.lastEnteredTarget_ = event.target; var item = event.target; - while (item && !(item instanceof DirectoryItem)) { + while (item && !(item instanceof cr.ui.TreeItem)) { item = item.parentNode; } diff --git a/ui/file_manager/file_manager/foreground/js/main_scripts.js b/ui/file_manager/file_manager/foreground/js/main_scripts.js index e06b761..e223892 100644 --- a/ui/file_manager/file_manager/foreground/js/main_scripts.js +++ b/ui/file_manager/file_manager/foreground/js/main_scripts.js @@ -107,7 +107,6 @@ //<include src="ui/conflict_dialog.js"/> //<include src="ui/file_manager_ui.js"/> //<include src="ui/multi_profile_share_dialog.js"/> -//<include src="ui/navigation_list.js"/> //<include src="ui/preview_panel.js"/> //<include src="ui/progress_center_panel.js"/> //<include src="ui/search_box.js"/> diff --git a/ui/file_manager/file_manager/foreground/js/ui/navigation_list.js b/ui/file_manager/file_manager/foreground/js/ui/navigation_list.js deleted file mode 100644 index 8de253d..0000000 --- a/ui/file_manager/file_manager/foreground/js/ui/navigation_list.js +++ /dev/null @@ -1,444 +0,0 @@ -// Copyright (c) 2012 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. - -'use strict'; - -/** - * A navigation list item. - * @constructor - * @extends {HTMLLIElement} - */ -var NavigationListItem = cr.ui.define('li'); - -NavigationListItem.prototype = { - __proto__: HTMLLIElement.prototype, - get modelItem() { return this.modelItem_; } -}; - -/** - * Decorate the item. - */ -NavigationListItem.prototype.decorate = function() { - // decorate() may be called twice: from the constructor and from - // List.createItem(). This check prevents double-decorating. - if (this.className) - return; - - this.className = 'root-item'; - this.setAttribute('role', 'option'); - - this.iconDiv_ = cr.doc.createElement('div'); - this.iconDiv_.className = 'volume-icon'; - this.appendChild(this.iconDiv_); - - this.label_ = cr.doc.createElement('div'); - this.label_.className = 'root-label entry-name'; - this.appendChild(this.label_); - - cr.defineProperty(this, 'lead', cr.PropertyKind.BOOL_ATTR); - cr.defineProperty(this, 'selected', cr.PropertyKind.BOOL_ATTR); -}; - -/** - * Associate a model with this item. - * @param {NavigationModelItem} modelItem NavigationModelItem of this item. - */ -NavigationListItem.prototype.setModelItem = function(modelItem) { - if (this.modelItem_) - console.warn('NavigationListItem.setModelItem should be called only once.'); - - this.modelItem_ = modelItem; - - var typeIcon; - if (modelItem.isVolume) { - if (modelItem.volumeInfo.volumeType == 'provided') { - var backgroundImage = '-webkit-image-set(' + - 'url(chrome://extension-icon/' + modelItem.volumeInfo.extensionId + - '/24/1) 1x, ' + - 'url(chrome://extension-icon/' + modelItem.volumeInfo.extensionId + - '/48/1) 2x);'; - // The icon div is not yet added to DOM, therefore it is impossible to - // use style.backgroundImage. - this.iconDiv_.setAttribute( - 'style', 'background-image: ' + backgroundImage); - } - typeIcon = modelItem.volumeInfo.volumeType; - } else if (modelItem.isShortcut) { - // Shortcuts are available for Drive only. - typeIcon = VolumeManagerCommon.VolumeType.DRIVE; - } - - this.iconDiv_.setAttribute('volume-type-icon', typeIcon); - - if (modelItem.isVolume) { - this.iconDiv_.setAttribute( - 'volume-subtype', modelItem.volumeInfo.deviceType); - } - - this.label_.textContent = modelItem.label; - - if (modelItem.isVolume && - (modelItem.volumeInfo.volumeType === - VolumeManagerCommon.VolumeType.ARCHIVE || - modelItem.volumeInfo.volumeType === - VolumeManagerCommon.VolumeType.REMOVABLE || - modelItem.volumeInfo.volumeType === - VolumeManagerCommon.VolumeType.PROVIDED)) { - this.eject_ = cr.doc.createElement('div'); - // Block other mouse handlers. - this.eject_.addEventListener( - 'mouseup', function(event) { event.stopPropagation() }); - this.eject_.addEventListener( - 'mousedown', function(event) { event.stopPropagation() }); - - this.eject_.className = 'root-eject'; - this.eject_.addEventListener('click', function(event) { - event.stopPropagation(); - cr.dispatchSimpleEvent(this, 'eject'); - }.bind(this)); - - this.appendChild(this.eject_); - } -}; - -/** - * Associate a context menu with this item. - * @param {cr.ui.Menu} menu Menu this item. - */ -NavigationListItem.prototype.maybeSetContextMenu = function(menu) { - if (!this.modelItem_) { - console.error('NavigationListItem.maybeSetContextMenu must be called ' + - 'after setModelItem().'); - return; - } - - // The context menu is shown on the following items: - // - Removable and Archive volumes - // - Folder shortcuts - if (this.modelItem_.isVolume && (this.modelItem_.volumeInfo.volumeType === - VolumeManagerCommon.VolumeType.REMOVABLE || - this.modelItem_.volumeInfo.volumeType === - VolumeManagerCommon.VolumeType.ARCHIVE || - this.modelItem_.volumeInfo.volumeType === - VolumeManagerCommon.VolumeType.PROVIDED) || - this.modelItem_.isShortcut) { - cr.ui.contextMenuHandler.setContextMenu(this, menu); - } -}; - -/** - * A navigation list. - * @constructor - * @extends {cr.ui.List} - */ -function NavigationList() { -} - -/** - * NavigationList inherits cr.ui.List. - */ -NavigationList.prototype = { - __proto__: cr.ui.List.prototype, - - set dataModel(dataModel) { - if (!this.onListContentChangedBound_) - this.onListContentChangedBound_ = this.onListContentChanged_.bind(this); - - if (this.dataModel_) { - this.dataModel_.removeEventListener( - 'change', this.onListContentChangedBound_); - this.dataModel_.removeEventListener( - 'permuted', this.onListContentChangedBound_); - } - - var parentSetter = cr.ui.List.prototype.__lookupSetter__('dataModel'); - parentSetter.call(this, dataModel); - - // This must be placed after the parent method is called, in order to make - // it sure that the list was changed. - dataModel.addEventListener('change', this.onListContentChangedBound_); - dataModel.addEventListener('permuted', this.onListContentChangedBound_); - }, - - get dataModel() { - return this.dataModel_; - }, - - // TODO(yoshiki): Add a setter of 'directoryModel'. -}; - -/** - * @param {HTMLElement} el Element to be DirectoryItem. - * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system. - * @param {DirectoryModel} directoryModel Current DirectoryModel. - * folders. - */ -NavigationList.decorate = function(el, volumeManager, directoryModel) { - el.__proto__ = NavigationList.prototype; - el.decorate(volumeManager, directoryModel); -}; - -/** - * @param {VolumeManagerWrapper} volumeManager The VolumeManager of the system. - * @param {DirectoryModel} directoryModel Current DirectoryModel. - */ -NavigationList.prototype.decorate = function(volumeManager, directoryModel) { - cr.ui.List.decorate(this); - this.__proto__ = NavigationList.prototype; - - this.directoryModel_ = directoryModel; - this.volumeManager_ = volumeManager; - this.selectionModel = new cr.ui.ListSingleSelectionModel(); - - this.directoryModel_.addEventListener('directory-changed', - this.onCurrentDirectoryChanged_.bind(this)); - this.selectionModel.addEventListener( - 'change', this.onSelectionChange_.bind(this)); - this.selectionModel.addEventListener( - 'beforeChange', this.onBeforeSelectionChange_.bind(this)); - - this.scrollBar_ = new ScrollBar(); - this.scrollBar_.initialize(this.parentNode, this); - - // Keeps track of selected model item to detect if it is changed actually. - this.currentModelItem_ = null; - - // Overriding default role 'list' set by cr.ui.List.decorate() to 'listbox' - // role for better accessibility on ChromeOS. - this.setAttribute('role', 'listbox'); - - var self = this; - this.itemConstructor = function(modelItem) { - return self.renderRoot_(modelItem); - }; -}; - -/** - * This overrides cr.ui.List.measureItem(). - * In the method, a temporary element is added/removed from the list, and we - * need to omit animations for such temporary items. - * - * @param {ListItem=} opt_item The list item to be measured. - * @return {{height: number, marginTop: number, marginBottom:number, - * width: number, marginLeft: number, marginRight:number}} Size. - * @override - */ -NavigationList.prototype.measureItem = function(opt_item) { - this.measuringTemporaryItemNow_ = true; - var result = cr.ui.List.prototype.measureItem.call(this, opt_item); - this.measuringTemporaryItemNow_ = false; - return result; -}; - -/** - * Creates an element of a navigation list. This method is called from - * cr.ui.List internally. - * - * @param {NavigationModelItem} modelItem NavigationModelItem to be rendered. - * @return {NavigationListItem} Rendered element. - * @private - */ -NavigationList.prototype.renderRoot_ = function(modelItem) { - var item = new NavigationListItem(); - item.setModelItem(modelItem); - - var handleClick = function() { - if (!item.selected) - return; - this.activateModelItem_(item.modelItem); - // On clicking the root item, clears the selection. - this.directoryModel_.clearSelection(); - }.bind(this); - item.addEventListener('click', handleClick); - - var handleEject = function() { - var unmountCommand = cr.doc.querySelector('command#unmount'); - // Let's make sure 'canExecute' state of the command is properly set for - // the root before executing it. - unmountCommand.canExecuteChange(item); - unmountCommand.execute(item); - }; - item.addEventListener('eject', handleEject); - - if (this.contextMenu_) - item.maybeSetContextMenu(this.contextMenu_); - - return item; -}; - -/** - * Sets a context menu. Context menu is enabled only on archive and removable - * volumes as of now. - * - * @param {cr.ui.Menu} menu Context menu. - */ -NavigationList.prototype.setContextMenu = function(menu) { - this.contextMenu_ = menu; - - for (var i = 0; i < this.dataModel.length; i++) { - this.getListItemByIndex(i).maybeSetContextMenu(this.contextMenu_); - } -}; - -/** - * Selects the n-th item from the list. - * @param {number} index Item index. - * @return {boolean} True for success, otherwise false. - */ -NavigationList.prototype.selectByIndex = function(index) { - if (index < 0 || index > this.dataModel.length - 1) - return false; - - this.selectionModel.selectedIndex = index; - this.activateModelItem_(this.dataModel.item(index)); - return true; -}; - - -/** - * Selects the passed item of the model. - * @param {NavigationModelItem} modelItem Model item to be activated. - * @private - */ -NavigationList.prototype.activateModelItem_ = function(modelItem) { - var onEntryResolved = function(entry) { - // Changes directory to the model item's root directory if needed. - if (!util.isSameEntry(this.directoryModel_.getCurrentDirEntry(), entry)) { - metrics.recordUserAction('FolderShortcut.Navigate'); - this.directoryModel_.changeDirectoryEntry(entry); - } - }.bind(this); - - if (modelItem.isVolume) { - modelItem.volumeInfo.resolveDisplayRoot( - onEntryResolved, - function() { - // Error, the display root is not available. It may happen on Drive. - this.dataModel.onItemNotFoundError(modelItem); - }.bind(this)); - } else if (modelItem.isShortcut) { - // For shortcuts we already have an Entry, but it has to be resolved again - // in case, it points to a non-existing directory. - var url = modelItem.entry.toURL(); - webkitResolveLocalFileSystemURL( - url, - onEntryResolved, - function() { - // Error, the entry can't be re-resolved. It may happen for shortcuts - // which targets got removed after resolving the Entry during - // initialization. - this.dataModel.onItemNotFoundError(modelItem); - }.bind(this)); - } -}; - -/** - * Handler before root item change. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onBeforeSelectionChange_ = function(event) { - if (event.changes.length == 1 && !event.changes[0].selected) - event.preventDefault(); -}; - -/** - * Handler for root item being clicked. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onSelectionChange_ = function(event) { - var index = this.selectionModel.selectedIndex; - if (index < 0 || index > this.dataModel.length - 1) - return; - - // If the selected model item is not changed actually, we don't change the - // current directory even if the selected index is changed. - var modelItem = this.dataModel.item(index); - if (modelItem === this.currentModelItem_) - return; - - // Remembers the selected model item. - this.currentModelItem_ = modelItem; - - // This handler is invoked even when the navigation list itself changes the - // selection. In such case, we shouldn't handle the event. - if (this.dontHandleSelectionEvent_) - return; - - this.activateModelItem_(modelItem); -}; - -/** - * Invoked when the current directory is changed. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onCurrentDirectoryChanged_ = function(event) { - this.selectBestMatchItem_(); -}; - -/** - * Invoked when the content in the data model is changed. - * @param {Event} event The event. - * @private - */ -NavigationList.prototype.onListContentChanged_ = function(event) { - this.selectBestMatchItem_(); -}; - -/** - * Synchronizes the volume list selection with the current directory, after - * it is changed outside of the volume list. - * @private - */ -NavigationList.prototype.selectBestMatchItem_ = function() { - var entry = this.directoryModel_.getCurrentDirEntry(); - // It may happen that the current directory is not set yet, for update events. - if (!entry) - return; - - // (1) Select the nearest shortcut directory. - var entryURL = entry.toURL(); - var bestMatchIndex = -1; - var bestMatchSubStringLen = 0; - for (var i = 0; i < this.dataModel.length; i++) { - var modelItem = this.dataModel.item(i); - if (!modelItem.isShortcut) - continue; - var modelItemURL = modelItem.entry.toURL(); - // Relying on URL's format is risky and should be avoided. However, there is - // no other way to quickly check if an entry is an ancestor of another one. - if (entryURL.indexOf(modelItemURL) === 0) { - if (bestMatchSubStringLen < modelItemURL.length) { - bestMatchIndex = i; - bestMatchSubStringLen = modelItemURL.length; - } - } - } - if (bestMatchIndex != -1) { - // Don't to invoke the handler of this instance, sets the guard. - this.dontHandleSelectionEvent_ = true; - this.selectionModel.selectedIndex = bestMatchIndex; - this.dontHandleSelectionEvent_ = false; - return; - } - - // (2) Selects the volume of the current directory. - var volumeInfo = this.volumeManager_.getVolumeInfo(entry); - if (!volumeInfo) - return; - for (var i = 0; i < this.dataModel.length; i++) { - var modelItem = this.dataModel.item(i); - if (!modelItem.isVolume) - continue; - if (modelItem.volumeInfo === volumeInfo) { - // Don't to invoke the handler of this instance, sets the guard. - this.dontHandleSelectionEvent_ = true; - this.selectionModel.selectedIndex = i; - this.dontHandleSelectionEvent_ = false; - return; - } - } -}; diff --git a/ui/file_manager/file_manager/main.html b/ui/file_manager/file_manager/main.html index 734b039..1a29a27 100644 --- a/ui/file_manager/file_manager/main.html +++ b/ui/file_manager/file_manager/main.html @@ -121,7 +121,6 @@ <script src="foreground/js/ui/conflict_dialog.js"></script> <script src="foreground/js/ui/file_manager_ui.js"></script> <script src="foreground/js/ui/multi_profile_share_dialog.js"></script> - <script src="foreground/js/ui/navigation_list.js"></script> <script src="foreground/js/ui/preview_panel.js"></script> <script src="foreground/js/ui/progress_center_panel.js"></script> <script src="foreground/js/ui/search_box.js"></script> @@ -291,7 +290,7 @@ <span id="profile-badge" hidden></span><span id="app-name"></span> </div> <div class="dialog-navigation-list-contents"> - <list id="navigation-list" tabindex="15"></list> + <tree id="directory-tree" tabindex="15"></tree> </div> <div class="dialog-navigation-list-footer"> <div id="progress-center" hidden> @@ -343,13 +342,6 @@ </div> <div class="dialog-body"> <div class="main-panel"> - <!-- The middle bar and spilitter are hidden by default, and will be shown by script if necessary. --> - <div class="dialog-middlebar-contents" hidden> - <div id="middlebar-header" - i18n-content="DRIVE_DIRECTORY_LABEL"></div> - <tree id="directory-tree" tabindex="16"></tree> - </div> - <div class="splitter" id="middlebar-splitter" hidden></div> <div class="filelist-panel"> <div class="drive-welcome header"></div> <div class="volume-warning" id="volume-space-warning" hidden></div> |