diff options
author | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-06 10:16:13 +0000 |
---|---|---|
committer | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-06 10:16:13 +0000 |
commit | 576383d6bcf037b6f66f4840c1443fa31b017bb8 (patch) | |
tree | 709280ce8b67a4ccde9c0665542fbe3ce952621e /chrome/browser | |
parent | ebd29ac51328ceab9bc834166de253a1a8950d86 (diff) | |
download | chromium_src-576383d6bcf037b6f66f4840c1443fa31b017bb8.zip chromium_src-576383d6bcf037b6f66f4840c1443fa31b017bb8.tar.gz chromium_src-576383d6bcf037b6f66f4840c1443fa31b017bb8.tar.bz2 |
Revert 113152 - [filebrowser] Add left panel with roots.
Not the final UI yet.
Additional improvements:
- file name is selected in save-as dialog at start;
- new folder moved to context menu, button deleted.
BUG=chromium-os:20168,chromium-os:22106,chromium-os:22105,chromium-os:22032,chromium-os:20547,chromium-os:20549
TEST=Manual
Review URL: http://codereview.chromium.org/8554003
Reason for revert: http://build.chromium.org/p/chromium.chromiumos/builders/Linux%20ChromeOS%20Aura/builds/1508
TBR=dgozman@chromium.org
Review URL: http://codereview.chromium.org/8818006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113176 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
8 files changed, 299 insertions, 630 deletions
diff --git a/chrome/browser/extensions/extension_file_browser_private_api.cc b/chrome/browser/extensions/extension_file_browser_private_api.cc index f82f854..c6456c0 100644 --- a/chrome/browser/extensions/extension_file_browser_private_api.cc +++ b/chrome/browser/extensions/extension_file_browser_private_api.cc @@ -1523,9 +1523,9 @@ bool FileDialogStringsFunction::RunImpl() { SET_STRING(IDS, WEB_FONT_SIZE); SET_STRING(IDS_FILE_BROWSER, ROOT_DIRECTORY_LABEL); + SET_STRING(IDS_FILE_BROWSER, DOWNLOADS_DIRECTORY_LABEL); SET_STRING(IDS_FILE_BROWSER, ARCHIVE_DIRECTORY_LABEL); SET_STRING(IDS_FILE_BROWSER, REMOVABLE_DIRECTORY_LABEL); - SET_STRING(IDS_FILE_BROWSER, CHROMEBOOK_DIRECTORY_LABEL); SET_STRING(IDS_FILE_BROWSER, NAME_COLUMN_LABEL); SET_STRING(IDS_FILE_BROWSER, SIZE_COLUMN_LABEL); SET_STRING(IDS_FILE_BROWSER, TYPE_COLUMN_LABEL); diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd index 0700717..9939df9 100644 --- a/chrome/browser/resources/component_extension_resources.grd +++ b/chrome/browser/resources/component_extension_resources.grd @@ -47,12 +47,6 @@ <include name="IDR_FILE_MANAGER_MEDIA_ENQUEUE_ICON" file="file_manager/images/icon_add_to_queue_16x16.png" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ARCHIVE_MOUNT_ICON" file="file_manager/images/icon_mount_archive_16x16.png" type="BINDATA" /> <include name="IDR_FILE_MANAGER_ARCHIVE_UNMOUNT_ICON" file="file_manager/images/icon_unmount_archive_16x16.png" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_OPEN_SIDEBAR_ICON" file="file_manager/images/open_sidebar.png" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_CLOSE_SIDEBAR_ICON" file="file_manager/images/close_sidebar.png" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_EJECT_ICON" file="file_manager/images/eject.png" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_ADD_DRIVE_ICON" file="file_manager/images/add_drive.png" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_CHROMEBOOK_24_ICON" file="file_manager/images/chromebook_24x24.png" type="BINDATA" /> - <include name="IDR_FILE_MANAGER_CHROMEBOOK_28_ICON" file="file_manager/images/chromebook_28x28.png" type="BINDATA" /> <include name="IDR_FILE_MANAGER_IMG_FILETYPE_AUDIO" file="file_manager/images/filetype_audio.png" type="BINDATA" /> <include name="IDR_FILE_MANAGER_IMG_FILETYPE_DEVICE" file="file_manager/images/filetype_device.png" type="BINDATA" /> diff --git a/chrome/browser/resources/file_manager/css/file_manager.css b/chrome/browser/resources/file_manager/css/file_manager.css index f4f2282..9e08d6a 100644 --- a/chrome/browser/resources/file_manager/css/file_manager.css +++ b/chrome/browser/resources/file_manager/css/file_manager.css @@ -100,176 +100,25 @@ input[type='submit'][disabled]:hover { padding-bottom: 8px; } -/* Main part of the dialog between header and footer. */ -.dialog-container { - display: -webkit-box; - -webkit-box-orient: horizontal; - -webkit-box-align: stretch; - overflow: hidden; - -webkit-box-flex: 1; -} - -/* List/grid and preview are inside this container. */ -.dialog-main { - -webkit-box-flex: 1; - display:-webkit-box; - -webkit-box-orient: vertical; - -webkit-box-align: stretch; -} - -/* Roots list at the left. */ -.dialog-sidebar { - position: relative; - -webkit-box-flex: 0; - width: 200px; - margin-left: -200px; - background-color: rgba(240, 240, 240, 1); - margin-bottom: 15px; - margin-top: 15px; - -webkit-border-top-right-radius: 4px; - -webkit-border-top-left-radius: 4px; - -webkit-border-bottom-left-radius: 4px; - -webkit-transition: margin-left 180ms ease; - overflow: hidden; -} - -.dialog-container[sidebar] .dialog-sidebar { - margin-left: 15px; -} - -/* Roots list at the left. */ -list.roots-list { - width: 100%; -} - -list.roots-list > * { - border: none; - border-radius: 0; - line-height: 35px; - margin: 0; - padding: 0 5px; - background-color: rgba(240,240,240,1); -} - -list.roots-list > [lead], -list.roots-list > [selected], -list.roots-list > [anchor] { - background-color: hsl(214,91%,89%); -} - -list.roots-list > [lead]:hover, -list.roots-list > [selected]:hover, -list.roots-list > [anchor]:hover { - background-color: hsl(214,91%,87%); -} - -list.roots-list li.root-item { - display: -webkit-box; - -webkit-box-align: center; - -webkit-box-pack: start; -} - -li.root-item > * { - display: block; - margin-right: 5px; -} - -li.root-item > .text { - max-width: 130px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -li.root-item > .spacer { - -webkit-box-flex: 1; -} - -img.root-eject { - opacity: 0.5; - cursor: pointer; - width: 15px; - height: 12px; -} - -img.root-eject:hover { - opacity: 1; -} - /* Breadcrumbs and things under the title but above the list view. */ .dialog-header { -webkit-box-orient: horizontal; -webkit-box-align: center; display: -webkit-box; - margin-top: 15px; - margin-right: 15px; + margin: 15px; margin-bottom: 4px; - margin-left: 15px; - -webkit-transition: all 180ms ease; - } - -/* Container for the detail and thumbnail (not implemented yet) list views. */ -.dialog-container[sidebar] .dialog-header { - margin-left: 0; -} - -/* Close sidebar button. */ -div.close-sidebar { - cursor: pointer; - position: absolute; - right: 0; - top: 2px; - display: none; - z-index: 10; - background-color: white; - border: 1px solid rgba(200,200,200,1); - width: 13px; - height: 24px; -} - -div.close-sidebar:hover { - background-color: rgba(240,240,240,1); -} - -/* Open sidebar button. */ -div.open-sidebar { - cursor: pointer; - margin-right: 10px; - background-color: white; - width: 13px; - height: 24px; -} - -div.open-sidebar:hover { - background-color: rgba(240,240,240,1); -} - -.dialog-container[sidebar] div.open-sidebar { - display: none;; -} - -.dialog-container[sidebar] div.close-sidebar { - display: block; } -/* Container for the detail and thumbnail list views. */ +/* Container for the detail and thumbnail (not implemented yet) list views. */ .dialog-body { -webkit-box-orient: vertical; -webkit-box-flex: 1; border: 1px #aaa solid; border-radius: 4px; display: -webkit-box; - margin-right: 15px; - margin-bottom: 15px; - margin-left: 15px; + margin: 15px; + margin-top: 0; overflow: hidden; - -webkit-transition: all 180ms ease; -} - -.dialog-container[sidebar] .dialog-body { - -webkit-border-top-left-radius: 0; - -webkit-border-bottom-left-radius: 0; - margin-left: 0; } /* Container for the ok/cancel buttons. */ @@ -285,7 +134,6 @@ div.open-sidebar:hover { -webkit-box-orient: horizontal; -webkit-box-flex: 1; display: -webkit-box; - -webkit-box-align: center; font-size: 15px; line-height: 15px; height: 18px; @@ -294,20 +142,6 @@ div.open-sidebar:hover { white-space: nowrap; } -.dialog-container[sidebar] .breadcrumbs { - margin-left: 10px; -} - -/* Icon at the start of breadcrumb path. Corresponds to the root selected. */ -.breadcrumb-icon { - margin-right: 5px; - display: block; -} - -.dialog-container[sidebar] .breadcrumb-icon { - display: none; -} - /* A single directory name in the list of path breadcrumbs. */ .breadcrumb-path { color: #265692; @@ -376,7 +210,10 @@ button.thumbnail-view > img { /* The cr.ui.Grid representing the detailed file list. */ .thumbnail-grid { - width: 100%; + position: absolute; + top: 0; + left: 0; + border: 0; overflow-y: scroll; } @@ -431,7 +268,9 @@ div.img-container > img { /* The cr.ui.Table representing the detailed file list. */ .detail-table { - width: 100%; + position: absolute; + top: 0; + left: 0; border: 0; } diff --git a/chrome/browser/resources/file_manager/js/file_manager.js b/chrome/browser/resources/file_manager/js/file_manager.js index a353e71..af830bb 100644 --- a/chrome/browser/resources/file_manager/js/file_manager.js +++ b/chrome/browser/resources/file_manager/js/file_manager.js @@ -63,7 +63,7 @@ function FileManager(dialogDom) { // TODO(dgozman): This will be changed to LocaleInfo. this.locale_ = new v8Locale(navigator.language); - this.initFileSystem_(); + this.resolveRoots_(); this.initDom_(); this.initDialogType_(); this.dialogDom_.style.opacity = '1'; @@ -475,13 +475,13 @@ FileManager.prototype = { // Instance methods. /** - * Request local file system, resolve roots and init_ after that. - * @private + * Request file system and get root entries asynchronously. Invokes init_ + * when have finished. */ - FileManager.prototype.initFileSystem_ = function() { - util.installFileErrorToString(); - metrics.startInterval('Load.FileSystem'); + FileManager.prototype.resolveRoots_ = function(callback) { + var rootPaths = ['Downloads', 'removable', 'archive']; + metrics.startInterval('Load.FileSystem'); var self = this; // The list of active mount points to distinct them from other directories. @@ -496,74 +496,41 @@ FileManager.prototype = { } chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { - metrics.recordTime('Load.FileSystem'); - self.filesystem_ = filesystem; - self.resolveRoots_(function(rootEntries) { - self.rootEntries_ = rootEntries; - onDone(); - }); - }); - }; + util.installFileErrorToString(); - /** - * Get root entries asynchronously. Invokes callback - * when have finished. - */ - FileManager.prototype.resolveRoots_ = function(callback) { - var rootPaths = [DOWNLOADS_DIRECTORY, ARCHIVE_DIRECTORY, - REMOVABLE_DIRECTORY].map(function(s) { return s.substring(1); }); - var rootEntries = []; + metrics.recordTime('Load.FileSystem'); - // The number of entries left to enumerate to get all roots. - // When equals to zero, we are done. - var entriesToEnumerate = 0; - // Entries may be enumerated faster than next one appears, so we have this - // guard to not finish too early. - var allEntriesFound = false; + var rootEntries = []; - function onPathError(path, err) { - console.error('Error locating root path: ' + path + ': ' + err); - } + function onAllRootsFound() { + metrics.recordTime('Load.Roots'); + self.rootEntries_ = rootEntries; + onDone(); + } - function onRootFound(root) { - if (root) { - rootEntries.push(root); - } else { - entriesToEnumerate--; - if (entriesToEnumerate == 0 && allEntriesFound) { - metrics.recordTime('Load.Roots'); - callback(rootEntries); - } + function onPathError(path, err) { + console.error('Error locating root path: ' + path + ': ' + err); } - } - function onEntryFound(entry) { - if (entry) { - entriesToEnumerate++; - var path = entry.fullPath; - if (path == ARCHIVE_DIRECTORY || path == REMOVABLE_DIRECTORY) { - // All removable devices and mounted archives are considered - // roots, and are shown in the sidebar. - util.forEachDirEntry(entry, onRootFound); + function onEntryFound(entry) { + if (entry) { + rootEntries.push(entry); } else { - onRootFound(entry); - onRootFound(null); + onAllRootsFound(); } - } else { - allEntriesFound = true; } - } - metrics.startInterval('Load.Roots'); - if (this.filesystem_.name.match(/^chrome-extension_\S+:external/i)) { - // We've been handed the local filesystem, whose root directory - // cannot be enumerated. - util.getDirectories(this.filesystem_.root, {create: false}, rootPaths, - onEntryFound, onPathError); - } else { - util.forEachDirEntry(this.filesystem_.root, onEntryFound); - } + metrics.startInterval('Load.Roots'); + if (filesystem.name.match(/^chrome-extension_\S+:external/i)) { + // We've been handed the local filesystem, whose root directory + // cannot be enumerated. + util.getDirectories(filesystem.root, {create: false}, rootPaths, + onEntryFound, onPathError); + } else { + util.forEachDirEntry(filesystem.root, onEntryFound); + } + }); }; /** @@ -571,7 +538,6 @@ FileManager.prototype = { */ FileManager.prototype.init_ = function() { metrics.startInterval('Load.DOM'); - this.initCommands_(); // TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is // available in all chrome trunk builds. @@ -629,7 +595,6 @@ FileManager.prototype = { // The list of archives requested to mount. We will show contents once // archive is mounted, but only for mounts from within this filebrowser tab. this.mountRequests_ = []; - this.unmountRequests_ = []; chrome.fileBrowserPrivate.onMountCompleted.addListener( this.onMountCompleted_.bind(this)); @@ -642,6 +607,8 @@ FileManager.prototype = { // all paste tasks are complete. this.pasteSuccessCallbacks_ = []; + this.initCommands_(); + this.setupCurrentDirectory_(); this.summarizeSelection_(); @@ -700,6 +667,7 @@ FileManager.prototype = { this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons'); this.okButton_ = this.dialogDom_.querySelector('.ok'); this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); + this.newFolderButton_ = this.dialogDom_.querySelector('.new-folder'); this.deleteButton_ = this.dialogDom_.querySelector('.delete-button'); this.downloadsWarning_ = @@ -730,11 +698,8 @@ FileManager.prototype = { this.okButton_.addEventListener('click', this.onOk_.bind(this)); this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); - this.dialogDom_.querySelector('div.open-sidebar').addEventListener( - 'click', this.onToggleSidebar_.bind(this)); - this.dialogDom_.querySelector('div.close-sidebar').addEventListener( - 'click', this.onToggleSidebar_.bind(this)); - this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); + this.dialogDom_.querySelector('button.new-folder').addEventListener( + 'click', this.onNewFolderButtonClick_.bind(this)); this.dialogDom_.querySelector('button.detail-view').addEventListener( 'click', this.onDetailViewButtonClick_.bind(this)); @@ -790,7 +755,6 @@ FileManager.prototype = { this.initTable_(); this.initGrid_(); - this.initRootsList_(); this.setListType(FileManager.ListType.DETAIL); @@ -799,39 +763,6 @@ FileManager.prototype = { this.textSearchState_ = {text: '', date: new Date()}; }; - FileManager.prototype.initRootsList_ = function() { - this.rootsList_ = this.dialogDom_.querySelector('.roots-list'); - cr.ui.List.decorate(this.rootsList_); - - var self = this; - this.rootsList_.itemConstructor = function(entry) { - return self.renderRoot_(entry); - }; - - this.rootsList_.selectionModel = new cr.ui.ListSingleSelectionModel(); - this.rootsList_.selectionModel.addEventListener( - 'change', this.onRootsSelectionChanged_.bind(this)); - - // TODO(dgozman): add "Add a drive" item. - this.rootsList_.dataModel = new cr.ui.ArrayDataModel(this.rootEntries_); - }; - - FileManager.prototype.updateRoots_ = function(opt_changeDirectoryTo) { - var self = this; - this.resolveRoots_(function(rootEntries) { - self.rootEntries_ = rootEntries; - - var dataModel = self.rootsList_.dataModel; - var args = [0, dataModel.length].concat(rootEntries); - dataModel.splice.apply(dataModel, args); - - self.updateRootsListSelection_(); - - if (opt_changeDirectoryTo) - self.changeDirectory(opt_changeDirectoryTo); - }); - }; - /** * Get the icon type for a given Entry. * @@ -859,8 +790,6 @@ FileManager.prototype = { } FileManager.prototype.computeIconType_ = function(entry) { - // TODO(dgozman): refactor this to use proper icons in left panel, - // and do not depend on mountPoints. var deviceNumber = this.getDeviceNumber(entry); if (deviceNumber != undefined) { if (this.mountPoints_[deviceNumber].mountCondition == '') @@ -1159,11 +1088,6 @@ FileManager.prototype = { !isSystemDirEntry(this.currentDirEntry_)) && this.selection && this.selection.totalCount > 0; - - case 'newfolder': - return this.currentDirEntry_ && - (this.dialogType_ == 'saveas-file' || - this.dialogType_ == 'full-page'); } }; @@ -1369,10 +1293,6 @@ FileManager.prototype = { case 'delete': this.deleteEntries(this.selection.entries); return; - - case 'newfolder': - this.onNewFolderCommand_(event); - return; } }; @@ -1396,6 +1316,10 @@ FileManager.prototype = { FileManager.prototype.onResize_ = function() { this.table_.style.height = this.grid_.style.height = this.grid_.parentNode.clientHeight + 'px'; + this.table_.style.width = this.grid_.style.width = + this.grid_.parentNode.clientWidth + 'px'; + + this.table_.list_.style.width = this.table_.parentNode.clientWidth + 'px'; this.table_.list_.style.height = (this.table_.clientHeight - 1 - this.table_.header_.clientHeight) + 'px'; @@ -1408,10 +1332,6 @@ FileManager.prototype = { } else { this.currentList_.redraw(); } - - this.rootsList_.style.height = - this.rootsList_.parentNode.clientHeight + 'px'; - this.rootsList_.redraw(); }; FileManager.prototype.resolvePath = function( @@ -1445,11 +1365,22 @@ FileManager.prototype = { // No preset given, find a good place to start. // Check for removable devices, if there are none, go to Downloads. var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) { - return isParentPath(REMOVABLE_DIRECTORY, rootEntry.fullPath); + return rootEntry.fullPath == REMOVABLE_DIRECTORY; })[0]; - var path = removableDirectoryEntry && removableDirectoryEntry.fullPath || - DOWNLOADS_DIRECTORY; - this.changeDirectory(path, CD_NO_HISTORY); + if (!removableDirectoryEntry) { + this.changeDirectory(DOWNLOADS_DIRECTORY, CD_NO_HISTORY); + return; + } + + var foundRemovable = false; + util.forEachDirEntry(removableDirectoryEntry, function(result) { + if (result) { + foundRemovable = true; + } else { // Done enumerating, and we know the answer. + this.changeDirectory(foundRemovable ? '/' : DOWNLOADS_DIRECTORY, + CD_NO_HISTORY); + } + }.bind(this)); }; FileManager.prototype.setupPath_ = function(path) { @@ -1486,7 +1417,6 @@ FileManager.prototype = { function onLeafError(err) { // Set filename first so OK button will update in changeDirectoryEntry. self.filenameInput_.value = leafName; - self.selectDefaultPathInFilenameInput_(); if (err = FileError.NOT_FOUND_ERR) { // Leaf does not exist, it's just a suggested file name. self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY); @@ -1502,7 +1432,6 @@ FileManager.prototype = { function onBaseError(err) { // Set filename first so OK button will update in changeDirectory. self.filenameInput_.value = leafName; - self.selectDefaultPathInFilenameInput_(); console.log('Unexpected error resolving default base "' + baseName + '": ' + err); self.changeDirectory('/', CD_NO_HISTORY); @@ -1748,6 +1677,8 @@ FileManager.prototype = { var div = this.document_.createElement('div'); div.className = 'filename-label'; var labelText = entry.name; + if (this.currentDirEntry_.name == '') + labelText = this.getLabelForRootPath_(labelText); div.textContent = labelText; div.entry = entry; @@ -1776,77 +1707,18 @@ FileManager.prototype = { return icon; }; - /** - * Return the localized name for the root. - * @param {string} path The full path of the root (starting with slash). - * @return {string} The localized name. - */ - FileManager.prototype.getRootLabel_ = function(path) { - if (path == DOWNLOADS_DIRECTORY) - return str('CHROMEBOOK_DIRECTORY_LABEL'); + FileManager.prototype.getLabelForRootPath_ = function(path) { + // This hack lets us localize the top level directories. + if (path == 'Downloads') + return str('DOWNLOADS_DIRECTORY_LABEL'); - if (path == ARCHIVE_DIRECTORY) + if (path == 'archive') return str('ARCHIVE_DIRECTORY_LABEL'); - if (isParentPath(ARCHIVE_DIRECTORY, path)) - return path.substring(ARCHIVE_DIRECTORY.length + 1); - if (path == REMOVABLE_DIRECTORY) + if (path == 'removable') return str('REMOVABLE_DIRECTORY_LABEL'); - if (isParentPath(REMOVABLE_DIRECTORY, path)) - return path.substring(REMOVABLE_DIRECTORY.length + 1); - - return path; - }; - FileManager.prototype.getRootIconUrl_ = function(path, opt_small) { - var iconUrl = opt_small ? 'images/chromebook_28x28.png' : - 'images/chromebook_24x24.png'; - if (isParentPath(REMOVABLE_DIRECTORY, path)) - iconUrl = 'images/filetype_device.png'; - else if (isParentPath(ARCHIVE_DIRECTORY, path)) - iconUrl = 'images/icon_mount_archive_16x16.png'; - return chrome.extension.getURL(iconUrl); - }; - - FileManager.prototype.renderRoot_ = function(entry) { - var li = this.document_.createElement('li'); - li.className = 'root-item'; - - var icon = this.document_.createElement('img'); - icon.src = this.getRootIconUrl_(entry.fullPath, false); - li.appendChild(icon); - - var div = this.document_.createElement('div'); - div.className = 'text'; - div.textContent = this.getRootLabel_(entry.fullPath); - li.appendChild(div); - - if (isParentPath(REMOVABLE_DIRECTORY, entry.fullPath) || - isParentPath(ARCHIVE_DIRECTORY, entry.fullPath)) { - var spacer = this.document_.createElement('div'); - spacer.className = 'spacer'; - li.appendChild(spacer); - - var eject = this.document_.createElement('img'); - eject.className = 'root-eject'; - eject.setAttribute('src', chrome.extension.getURL('images/eject.png')); - eject.addEventListener('click', this.onEjectClick_.bind(this, entry)); - li.appendChild(eject); - } - - cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); - cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); - return li; - }; - - /** - * Handler for eject button clicked. - * @param {Entry} entry Entry to eject. - * @param {Event} event The event. - */ - FileManager.prototype.onEjectClick_ = function(entry, event) { - this.unmountRequests_.push(entry.toURL()); - chrome.fileBrowserPrivate.removeMount(entry.fullPath); + return path || str('ROOT_DIRECTORY_LABEL'); }; /** @@ -1865,7 +1737,13 @@ FileManager.prototype = { label.appendChild(this.renderIconType_(entry, columnId, table)); label.entry = entry; label.className = 'detail-name'; - label.appendChild(this.document_.createTextNode(entry.name)); + if (this.currentDirEntry_.name == '') { + label.appendChild(this.document_.createTextNode( + this.getLabelForRootPath_(entry.name))); + } else { + label.appendChild(this.document_.createTextNode(entry.name)); + } + return label; }; @@ -2248,6 +2126,7 @@ FileManager.prototype = { // These are done in separate functions, as the checks require // asynchronous function calls. + this.maybeRenderUnmountTask_(selection); this.maybeRenderFormattingTask_(selection); }; @@ -2269,6 +2148,38 @@ FileManager.prototype = { }; /** + * Checks whether unmount task should be displayed and if the answer is + * affirmative renders it. + * @param {Object} selection Selected files object. + */ + FileManager.prototype.maybeRenderUnmountTask_ = function(selection) { + for (var index = 0; index < selection.urls.length; ++index) { + // Each url should be a mount point. + var path = selection.entries[index].fullPath; + var found = false; + for (var i = 0; i < this.mountPoints_.length; i++) { + var mountPath = this.mountPoints_[i].mountPath; + if (mountPath[0] != '/') { + mountPath = '/' + mountPath; + } + if (mountPath == path && this.mountPoints_[i].mountType == 'file') { + found = true; + break; + } + } + if (!found) + return; + } + this.renderTaskButton_({ + taskId: this.getExtensionId_() + '|unmount-archive', + iconUrl: + chrome.extension.getURL('images/icon_unmount_archive_16x16.png'), + title: str('UNMOUNT_ARCHIVE'), + internal: true + }); + }; + + /** * Checks whether formatting task should be displayed and if the answer is * affirmative renders it. Includes asynchronous calls, so it's splitted into * three parts. @@ -2349,49 +2260,44 @@ FileManager.prototype = { var self = this; chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { self.mountPoints_ = mountPoints; - var changeDirectoryTo = null; - if (event.eventType == 'mount') { - // Mount request finished - remove it. - var index = self.mountRequests_.indexOf(event.sourceUrl); - if (index != -1) { - self.mountRequests_.splice(index, 1); - // Go to mounted directory, if request was initiated from this tab. - if (event.status == 'success') - changeDirectoryTo = event.mountPath; + for (var index = 0; index < self.mountRequests_.length; ++index) { + if (self.mountRequests_[index] == event.sourceUrl) { + self.mountRequests_.splice(index, 1); + if (event.status == 'success') { + self.changeDirectory(event.mountPath); + } else { + // Report mount error. + if (event.mountType == 'file') { + var fileName = event.sourceUrl.substr( + event.sourceUrl.lastIndexOf('/') + 1); + self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName, + event.status)); + } + } + return; + } } } - if (event.eventType == 'unmount') { - // Unmount request finished - remove it. - var index = self.unmountRequests_.indexOf(event.sourceUrl); - if (index != -1) - self.unmountRequests_.splice(index, 1); - } - - if (event.eventType == 'mount' && event.status != 'success' && - event.mountType == 'file') { - // Report mount error. - var fileName = event.sourceUrl.substr( - event.sourceUrl.lastIndexOf('/') + 1); - self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName, - event.status)); - } - - if (event.eventType == 'unmount' && event.status != 'success') { - // Report unmount error. - // TODO(dgozman): introduce string and show alert here. - } - if (event.eventType == 'unmount' && event.status == 'success' && self.currentDirEntry_ && isParentPath(event.mountPath, self.currentDirEntry_.fullPath)) { - changeDirectoryTo = getParentPath(event.mountPath); + self.changeDirectory(getParentPath(event.mountPath)); + return; } - // In the case of success, roots are changed and should be rescanned. - if (event.status == 'success') - self.updateRoots_(changeDirectoryTo); + var rescanDirectoryNeeded = (event.status == 'success'); + for (var i = 0; i < mountPoints.length; i++) { + if (event.sourceUrl == mountPoints[i].sourceUrl && + mountPoints[i].mountCondition != '') { + rescanDirectoryNeeded = true; + } + } + // TODO(dgozman): rescan directory, only if it contains mounted points, + // when mounts location will be decided. + if (rescanDirectoryNeeded) + self.rescanDirectory_(null, 300); }); }; @@ -2410,6 +2316,10 @@ FileManager.prototype = { this.mountRequests_.push(urls[index]); chrome.fileBrowserPrivate.addMount(urls[index], 'file', {}); } + } else if (id == 'unmount-archive') { + for (var index = 0; index < urls.length; ++index) { + chrome.fileBrowserPrivate.removeMount(urls[index]); + } } else if (id == 'format-device') { this.confirm.show(str('FORMATTING_WARNING'), function() { chrome.fileBrowserPrivate.formatDevice(urls[0]); @@ -2486,15 +2396,6 @@ FileManager.prototype = { galleryFrame.focus(); }; - FileManager.prototype.getRootForPath_ = function(path) { - for (var index = 0; index < this.rootEntries_.length; index++) { - if (isParentPath(this.rootEntries_[index].fullPath, path)) { - return index; - } - } - return -1; - }; - /** * Update the breadcrumb display to reflect the current directory. */ @@ -2502,41 +2403,23 @@ FileManager.prototype = { var bc = this.dialogDom_.querySelector('.breadcrumbs'); removeChildren(bc); - var fullPath = this.currentDirEntry_.fullPath; - var rootIndex = this.getRootForPath_(fullPath); - if (rootIndex == -1) { - console.error('Not root for: ' + fullPath); - return; - } - var root = this.rootEntries_[rootIndex]; - - var icon = this.document_.createElement('img'); - icon.className = 'breadcrumb-icon'; - icon.setAttribute('src', this.getRootIconUrl_(root.fullPath, true)); - bc.appendChild(icon); - - var rootPath = root.fullPath; - var relativePath = fullPath.substring(rootPath.length); - var pathNames = relativePath.replace(/\/$/, '').split('/'); - if (pathNames[0] == '') - pathNames.splice(0, 1); - - // We need a first breadcrumb for root, so placing last name from - // rootPath as first name of relativePath. - var rootPathNames = rootPath.replace(/\/$/, '').split('/'); - pathNames.splice(0, 0, rootPathNames[rootPathNames.length - 1]); - rootPathNames.splice(rootPathNames.length - 1, 1); - var path = rootPathNames.join('/') + '/'; + var fullPath = this.currentDirEntry_.fullPath.replace(/\/$/, ''); + var pathNames = fullPath.split('/'); + var path = ''; for (var i = 0; i < pathNames.length; i++) { var pathName = pathNames[i]; - path += pathName; + path += pathName + '/'; var div = this.document_.createElement('div'); div.className = 'breadcrumb-path'; - div.textContent = i == 0 ? this.getRootLabel_(path) : pathName; + if (i <= 1) { + // i == 0: root directory itself, i == 1: the files it contains. + div.textContent = this.getLabelForRootPath_(pathName); + } else { + div.textContent = pathName; + } - path = path + '/'; div.path = path; div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); @@ -2640,17 +2523,6 @@ FileManager.prototype = { } }; - FileManager.prototype.updateRootsListSelection_ = function() { - if (!this.currentDirEntry_) return; - var index = this.getRootForPath_(this.currentDirEntry_.fullPath); - if (index == -1) { - this.rootsList_.selectionModel.selectedIndex = 0; - } else { - if (this.rootsList_.selectionModel.selectedIndex != index) - this.rootsList_.selectionModel.selectedIndex = index; - } - }; - FileManager.prototype.selectIndex = function(index) { this.currentList_.focus(); if (index >= this.dataModel_.length) @@ -2774,16 +2646,6 @@ FileManager.prototype = { opt_saveHistory = !!opt_saveHistory; } - // Some directories are above roots, so we instead show the first root. - // There may be request to change directory above the roots. For example, - // when usb-dirve is removed, we try to change to the parent directory, - // which is REMOVABLE_DIRECTORY. - if (!dirEntry || dirEntry.fullPath == '/' || - dirEntry.fullPath == REMOVABLE_DIRECTORY || - dirEntry.fullPath == ARCHIVE_DIRECTORY) { - dirEntry = this.rootEntries_[0] || dirEntry; - } - var location = document.location.origin + document.location.pathname + '#' + encodeURI(dirEntry.fullPath); if (opt_saveHistory) { @@ -3023,25 +2885,6 @@ FileManager.prototype = { } }; - FileManager.prototype.onRootsSelectionChanged_ = function(event) { - var root = this.rootEntries_[this.rootsList_.selectionModel.selectedIndex]; - this.changeDirectoryEntry(root); - }; - - FileManager.prototype.selectDefaultPathInFilenameInput_ = function() { - var input = this.filenameInput_; - input.focus(); - var selectionEnd = input.value.lastIndexOf('.'); - if (selectionEnd == -1) { - input.select(); - } else { - input.selectionStart = 0; - input.selectionEnd = selectionEnd; - } - // Clear, so we never do this again. - this.params_.defaultPath = ''; - }; - /** * Update the UI when the selection model changes. * @@ -3056,12 +2899,8 @@ FileManager.prototype = { if (this.selection && this.selection.totalCount == 1 && - this.selection.entries[0].isFile && - this.filenameInput_.value != this.selection.entries[0].name) { + this.selection.entries[0].isFile) this.filenameInput_.value = this.selection.entries[0].name; - if (this.params_.defaultPath == this.selection.entries[0].fullPath) - this.selectDefaultPathInFilenameInput_(); - } } this.updateOkButton_(); @@ -3214,7 +3053,9 @@ FileManager.prototype = { this.checkFreeSpace_(this.currentDirEntry_.fullPath); - // TODO(dgozman): title may be better than this. + // New folder should never be enabled in the root or media/ directories. + this.newFolderButton_.disabled = isSystemDirEntry(this.currentDirEntry_); + this.document_.title = this.currentDirEntry_.fullPath; var self = this; @@ -3312,101 +3153,113 @@ FileManager.prototype = { this.currentList_.selectionModel.clear(); this.updateBreadcrumbs_(); - this.updateRootsListSelection_(); - // Add current request to pending result list - this.pendingRescanQueue_.push({ - onSuccess:opt_callback, - onError:opt_onError - }); - - if (this.rescanRunning_) - return; - - this.rescanRunning_ = true; - - // The current list of callbacks is saved and reset. Subsequent - // calls to rescanDirectory_ while we're still pending will be - // saved and will cause an additional rescan to happen after a delay. - var callbacks = this.pendingRescanQueue_; - - this.pendingRescanQueue_ = []; + if (this.currentDirEntry_.fullPath != '/') { + // Add current request to pending result list + this.pendingRescanQueue_.push({ + onSuccess:opt_callback, + onError:opt_onError + }); - var self = this; - var reader; + if (this.rescanRunning_) + return; - function onError() { - if (self.pendingRescanQueue_.length > 0) { - setTimeout(self.rescanDirectory_.bind(self), - SIMULTANEOUS_RESCAN_INTERVAL); - } + this.rescanRunning_ = true; - self.rescanRunning_ = false; + // The current list of callbacks is saved and reset. Subsequent + // calls to rescanDirectory_ while we're still pending will be + // saved and will cause an additional rescan to happen after a delay. + var callbacks = this.pendingRescanQueue_; - for (var i= 0; i < callbacks.length; i++) { - if (callbacks[i].onError) - try { - callbacks[i].onError(); - } catch (ex) { - console.error('Caught exception while notifying about error: ' + - name, ex); - } - } - } + this.pendingRescanQueue_ = []; - function onReadSome(entries) { - if (entries.length == 0) { - metrics.recordTime('DirectoryScan'); - if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) { - metrics.reportCount("DownloadsCount", self.dataModel_.length); - } + var self = this; + var reader; + function onError() { if (self.pendingRescanQueue_.length > 0) { setTimeout(self.rescanDirectory_.bind(self), SIMULTANEOUS_RESCAN_INTERVAL); } self.rescanRunning_ = false; + for (var i= 0; i < callbacks.length; i++) { - if (callbacks[i].onSuccess) + if (callbacks[i].onError) try { - callbacks[i].onSuccess(); + callbacks[i].onError(); } catch (ex) { console.error('Caught exception while notifying about error: ' + name, ex); } } - - return; } - // Splice takes the to-be-spliced-in array as individual parameters, - // rather than as an array, so we need to perform some acrobatics... - var spliceArgs = [].slice.call(entries); + function onReadSome(entries) { + if (entries.length == 0) { + metrics.recordTime('DirectoryScan'); + if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) { + metrics.reportCount("DownloadsCount", self.dataModel_.length); + } - // Hide files that start with a dot ('.'). - // TODO(rginda): User should be able to override this. Support for other - // commonly hidden patterns might be nice too. - if (self.filterFiles_) { - spliceArgs = spliceArgs.filter(function(e) { - return e.name.substr(0, 1) != '.'; - }); - } + if (self.pendingRescanQueue_.length > 0) { + setTimeout(self.rescanDirectory_.bind(self), + SIMULTANEOUS_RESCAN_INTERVAL); + } - self.prefetchCacheForSorting_(spliceArgs, function() { - spliceArgs.unshift(0, 0); // index, deleteCount - self.dataModel_.splice.apply(self.dataModel_, spliceArgs); + self.rescanRunning_ = false; + for (var i= 0; i < callbacks.length; i++) { + if (callbacks[i].onSuccess) + try { + callbacks[i].onSuccess(); + } catch (ex) { + console.error('Caught exception while notifying about error: ' + + name, ex); + } + } - // Keep reading until entries.length is 0. - reader.readEntries(onReadSome, onError); - }); - }; + return; + } + + // Splice takes the to-be-spliced-in array as individual parameters, + // rather than as an array, so we need to perform some acrobatics... + var spliceArgs = [].slice.call(entries); + + // Hide files that start with a dot ('.'). + // TODO(rginda): User should be able to override this. Support for other + // commonly hidden patterns might be nice too. + if (self.filterFiles_) { + spliceArgs = spliceArgs.filter(function(e) { + return e.name.substr(0, 1) != '.'; + }); + } - metrics.startInterval('DirectoryScan'); + self.prefetchCacheForSorting_(spliceArgs, function() { + spliceArgs.unshift(0, 0); // index, deleteCount + self.dataModel_.splice.apply(self.dataModel_, spliceArgs); - // If not the root directory, just read the contents. - reader = this.currentDirEntry_.createReader(); - reader.readEntries(onReadSome, onError); + // Keep reading until entries.length is 0. + reader.readEntries(onReadSome, onError); + }); + }; + + metrics.startInterval('DirectoryScan'); + + // If not the root directory, just read the contents. + reader = this.currentDirEntry_.createReader(); + reader.readEntries(onReadSome, onError); + return; + } + + // Otherwise, use the provided list of root subdirectories, since the + // real local filesystem root directory (the one we use outside the + // harness) can't be enumerated yet. + var spliceArgs = [].slice.call(this.rootEntries_); + spliceArgs.unshift(0, 0); // index, deleteCount + this.dataModel_.splice.apply(this.dataModel_, spliceArgs); + + if (opt_callback) + opt_callback(); }; FileManager.prototype.prefetchCacheForSorting_ = function(entries, callback) { @@ -3660,17 +3513,7 @@ FileManager.prototype = { }, 0); }; - FileManager.prototype.onToggleSidebar_ = function(event) { - if (this.dialogContainer_.hasAttribute('sidebar')) { - this.dialogContainer_.removeAttribute('sidebar'); - } else { - this.dialogContainer_.setAttribute('sidebar', 'sidebar'); - } - // TODO(dgozman): make table header css-resizable. - setTimeout(this.onResize_.bind(this), 300); - }; - - FileManager.prototype.onNewFolderCommand_ = function(event) { + FileManager.prototype.onNewFolderButtonClick_ = function(event) { var self = this; function onNameSelected(name) { @@ -3799,10 +3642,9 @@ FileManager.prototype = { break; case 32: // Ctrl-Space => New Folder. - if ((this.dialogType_ == 'saveas-file' || - this.dialogType_ == 'full-page') && event.ctrlKey) { + if (this.newFolderButton_.style.display != 'none' && event.ctrlKey) { event.preventDefault(); - this.onNewFolderCommand_(); + this.onNewFolderButtonClick_(); } break; diff --git a/chrome/browser/resources/file_manager/js/harness.js b/chrome/browser/resources/file_manager/js/harness.js index 1022852..b68f9c0 100644 --- a/chrome/browser/resources/file_manager/js/harness.js +++ b/chrome/browser/resources/file_manager/js/harness.js @@ -19,11 +19,7 @@ var harness = { console.log('Filesystem found.'); self.filesystem = filesystem; util.getOrCreateDirectory(filesystem.root, '/Downloads', function () {}); - util.getOrCreateDirectory(filesystem.root, '/removable', function () {}); - util.getOrCreateDirectory(filesystem.root, '/removable/disk1', - function () {}); - util.getOrCreateDirectory(filesystem.root, '/removable/disk2', - function () {}); + util.getOrCreateDirectory(filesystem.root, '/media', function () {}); }; window.webkitRequestFileSystem(window.PERSISTENT, 16 * 1024 * 1024, diff --git a/chrome/browser/resources/file_manager/js/mock_chrome.js b/chrome/browser/resources/file_manager/js/mock_chrome.js index 7348b68..17898e4 100644 --- a/chrome/browser/resources/file_manager/js/mock_chrome.js +++ b/chrome/browser/resources/file_manager/js/mock_chrome.js @@ -217,7 +217,7 @@ chrome.fileBrowserPrivate = { PARENT_DIRECTORY: 'Parent Directory', ROOT_DIRECTORY_LABEL: 'Files', - CHROMEBOOK_DIRECTORY_LABEL: 'Chromebook', + DOWNLOADS_DIRECTORY_LABEL: 'File Shelf', DOWNLOADS_DIRECTORY_WARNING: "<strong>Caution:</strong> These files are temporary and may be automatically deleted to free up disk space. <a href='javascript://'>Learn More</a>", MEDIA_DIRECTORY_LABEL: 'External Storage', NAME_COLUMN_LABEL: 'Name', diff --git a/chrome/browser/resources/file_manager/main.html b/chrome/browser/resources/file_manager/main.html index cf75ff7..cb22317 100644 --- a/chrome/browser/resources/file_manager/main.html +++ b/chrome/browser/resources/file_manager/main.html @@ -109,69 +109,59 @@ <body i18n-values=".style.fontFamily:WEB_FONT_FAMILY; .style.fontSize:WEB_FONT_SIZE"> <commands> - <command id="cut" i18n-values="label:CUT_BUTTON_LABEL"></command> - <command id="copy" i18n-values="label:COPY_BUTTON_LABEL"></command> - <command id="paste" i18n-values="label:PASTE_BUTTON_LABEL"></command> - <command id="rename" i18n-values="label:RENAME_BUTTON_LABEL"></command> - <command id="delete" i18n-values="label:DELETE_BUTTON_LABEL"></command> - <command id="newfolder" i18n-values="label:NEW_FOLDER_BUTTON_LABEL"></command> + <command id="cut"></command> + <command id="copy"></command> + <command id="paste"></command> + <command id="rename"></command> + <command id="delete"></command> </commands> <menu class=file-context-menu> - <menuitem command='#cut'></menuitem> - <menuitem command='#copy'></menuitem> - <menuitem command='#paste'></menuitem> + <menuitem i18n-content=CUT_BUTTON_LABEL command='#cut'></menuitem> + <menuitem i18n-content=COPY_BUTTON_LABEL command='#copy'></menuitem> + <menuitem i18n-content=PASTE_BUTTON_LABEL command='#paste'></menuitem> <hr> - <menuitem command='#rename'></menuitem> - <menuitem command='#delete'></menuitem> - <hr visibleif='this.dialogType_ == "saveas-file" || - this.dialogType_ == "full-page"'> - <menuitem command='#newfolder' - visibleif='this.dialogType_ == "saveas-file" || - this.dialogType_ == "full-page"'></menuitem> + <menuitem i18n-content=RENAME_BUTTON_LABEL command='#rename'></menuitem> + <menuitem i18n-content=DELETE_BUTTON_LABEL command='#delete'></menuitem> </menu> <div class=dialog-title visibleif='this.dialogType_ != "full-page"' >[TITLE]</div> - <div class=dialog-container> - <div class=dialog-sidebar> - <div class=close-sidebar><img src='images/close_sidebar.png'></div> - <list class=roots-list></list> - </div> - <div class=dialog-main> - <div class=dialog-header> - <div class=open-sidebar><img src='images/open_sidebar.png'></div> - <div class=breadcrumbs></div> - <button class=detail-view tabindex=4 - ><img src='images/icon-detail-view.png'></button - ><button class=thumbnail-view tabindex=5 - ><img src='images/icon-thumb-view.png'></button> - </div> - <div class=dialog-body> - <div class=filelist-panel> - <div class=list-container> - <div class=detail-table tabindex=0></div> - <grid class=thumbnail-grid tabindex=0></grid> - </div> - <div class=downloads-warning hidden> - <img src=images/warning_icon_square_26x26.png> - <div></div> - </div> - </div> - <div class=preview-panel visibility=hidden> - <div><div class=preview-thumbnails></div></div> - <div><div class=preview-summary></div></div> - <div class=task-buttons></div> - <div> - <button class='delete-button task-button' command='#delete' - onclick='fileManager.deleteEntries( - fileManager.selection.entries, false)' - visibleif='this.dialogType_ == "full-page"' - ><img src='images/button-icon-delete.png' - ><div i18n-content=DELETE_BUTTON_LABEL></div + <div class=dialog-header> + <div class=breadcrumbs></div> + <button class=detail-view tabindex=4 + ><img src='images/icon-detail-view.png'></button + ><button class=thumbnail-view tabindex=5 + ><img src='images/icon-thumb-view.png'></button> + <button i18n-content=NEW_FOLDER_BUTTON_LABEL class='new-folder' + tabindex=6 + visibleif='this.dialogType_ == "saveas-file" || + this.dialogType_ == "full-page"' ></button> - </div> - </div> + </div> + <div class=dialog-body> + <div class=filelist-panel> + <div class=list-container> + <div class=detail-table tabindex=0></div> + <grid class=thumbnail-grid tabindex=0></grid> + </div> + <div class=downloads-warning hidden> + <img src=images/warning_icon_square_26x26.png> + <div></div> + </div> + </div> + <div class=preview-panel visibility=hidden> + <div><div class=preview-thumbnails></div></div> + <div><div class=preview-summary></div></div> + <div class=task-buttons></div> + <div> + <button class='delete-button task-button' command='#delete' + onclick='fileManager.deleteEntries( + fileManager.selection.entries, false)' + visibleif='this.dialogType_ == "full-page"' + ><img src='images/button-icon-delete.png' + ><div i18n-content=DELETE_BUTTON_LABEL></div + ></button> </div> </div> </div> diff --git a/chrome/browser/resources/file_manager/manifest.json b/chrome/browser/resources/file_manager/manifest.json index be35781..326665e 100644 --- a/chrome/browser/resources/file_manager/manifest.json +++ b/chrome/browser/resources/file_manager/manifest.json @@ -89,6 +89,14 @@ ] }, { + "id": "unmount-archive", + "default_title": "__MSG_UNMOUNT_ARCHIVE__", + "default_icon": "images/icon_unmount_archive_16x16.png", + "file_filters": [ + "filesystem:*.mounted_zip" + ] + }, + { "id": "gallery", "default_title": "__MSG_GALLERY__", "default_icon": "images/icon_preview_16x16.png", |