Index: chrome/browser/resources/file_manager/js/file_manager.js |
=================================================================== |
--- chrome/browser/resources/file_manager/js/file_manager.js (revision 111153) |
+++ chrome/browser/resources/file_manager/js/file_manager.js (working copy) |
@@ -65,7 +65,7 @@ |
// TODO(dgozman): This will be changed to LocaleInfo. |
this.locale_ = new v8Locale(navigator.language); |
- this.resolveRoots_(); |
+ this.initFileSystem_(); |
this.initDom_(); |
this.initDialogType_(); |
this.dialogDom_.style.opacity = '1'; |
@@ -467,13 +467,12 @@ |
// Instance methods. |
/** |
- * Request file system and get root entries asynchronously. Invokes init_ |
- * when have finished. |
+ * Request local file system, resolve roots and init_ after that. |
*/ |
- FileManager.prototype.resolveRoots_ = function(callback) { |
- var rootPaths = ['Downloads', 'removable', 'archive']; |
+ FileManager.prototype.initFileSystem_ = function() { |
+ util.installFileErrorToString(); |
+ metrics.startInterval('RequestLocalFileSystem'); |
- metrics.startInterval('RequestLocalFileSystem'); |
var self = this; |
// The list of active mount points to distinct them from other directories. |
@@ -488,41 +487,75 @@ |
} |
chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { |
- self.filesystem_ = filesystem; |
- util.installFileErrorToString(); |
- |
metrics.recordTime('RequestLocalFileSystem'); |
console.log('Found filesystem: ' + filesystem.name, filesystem); |
- var rootEntries = []; |
- |
- function onAllRootsFound() { |
+ self.filesystem_ = filesystem; |
+ self.resolveRoots_(function(rootEntries) { |
self.rootEntries_ = rootEntries; |
onDone(); |
- } |
+ }); |
+ }); |
+ }; |
- function onPathError(path, err) { |
- console.error('Error locating root path: ' + path + ': ' + err); |
+ /** |
+ * 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 = []; |
+ |
+ // 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; |
+ |
+ function onPathError(path, err) { |
+ console.error('Error locating root path: ' + path + ': ' + err); |
+ } |
+ |
+ function onRootFound(root) { |
+ if (root) { |
+ rootEntries.push(root); |
+ } else { |
+ entriesToEnumerate--; |
+ if (entriesToEnumerate == 0 && allEntriesFound) { |
+ metrics.recordTime('EnumerateRoots'); |
+ callback(rootEntries); |
+ } |
} |
+ } |
- function onEntryFound(entry) { |
- if (entry) { |
- rootEntries.push(entry); |
+ 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); |
} else { |
- onAllRootsFound(); |
+ onRootFound(entry); |
+ onRootFound(null); |
} |
+ } else { |
+ allEntriesFound = true; |
} |
+ } |
- metrics.startInterval('EnumerateRoots'); |
- 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); |
- } |
- }); |
+ metrics.startInterval('EnumerateRoots'); |
+ 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); |
+ } |
}; |
/** |
@@ -530,6 +563,7 @@ |
*/ |
FileManager.prototype.init_ = function() { |
metrics.startInterval('InitFileManager'); |
+ this.initCommands_(); |
// TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is |
// available in all chrome trunk builds. |
@@ -587,6 +621,7 @@ |
// 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)); |
@@ -599,8 +634,6 @@ |
// all paste tasks are complete. |
this.pasteSuccessCallbacks_ = []; |
- this.initCommands_(); |
- |
this.setupCurrentDirectory_(); |
this.summarizeSelection_(); |
@@ -622,6 +655,8 @@ |
for (var i = 0; i < commands.length; i++) { |
var command = commands[i]; |
cr.ui.Command.decorate(command); |
+ command.label = command.textContent; |
SeRya
2011/11/28 10:30:55
Right way to int-ze the labes is using 'i18-values
dgozman
2011/11/28 11:45:53
Done.
|
+ command.textContent = ''; |
this.commands_[command.id] = command; |
} |
@@ -659,7 +694,6 @@ |
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_ = |
@@ -690,8 +724,11 @@ |
this.okButton_.addEventListener('click', this.onOk_.bind(this)); |
this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); |
- this.dialogDom_.querySelector('button.new-folder').addEventListener( |
- 'click', this.onNewFolderButtonClick_.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.detail-view').addEventListener( |
'click', this.onDetailViewButtonClick_.bind(this)); |
@@ -744,6 +781,7 @@ |
this.initTable_(); |
this.initGrid_(); |
+ this.initRootsList_(); |
this.setListType(FileManager.ListType.DETAIL); |
@@ -752,6 +790,39 @@ |
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. |
* |
@@ -1071,6 +1142,11 @@ |
!isSystemDirEntry(this.currentDirEntry_)) && |
this.selection && |
this.selection.totalCount > 0; |
+ |
+ case 'newfolder': |
+ return this.currentDirEntry_ && |
+ (this.dialogType_ == 'saveas-file' || |
+ this.dialogType_ == 'full-page'); |
} |
}; |
@@ -1278,6 +1354,10 @@ |
case 'delete': |
this.deleteEntries(this.selection.entries); |
return; |
+ |
+ case 'newfolder': |
+ this.onNewFolderCommand_(event); |
+ return; |
} |
}; |
@@ -1301,10 +1381,6 @@ |
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'; |
@@ -1317,6 +1393,10 @@ |
} else { |
this.currentList_.redraw(); |
} |
+ |
+ this.rootsList_.style.height = |
+ this.rootsList_.parentNode.clientHeight + 'px'; |
+ this.rootsList_.redraw(); |
}; |
FileManager.prototype.resolvePath = function( |
@@ -1350,22 +1430,11 @@ |
// 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 rootEntry.fullPath == REMOVABLE_DIRECTORY; |
+ return isParentPath(REMOVABLE_DIRECTORY, rootEntry.fullPath); |
})[0]; |
- 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)); |
+ this.changeDirectory( |
+ removableDirectoryEntry.fullPath || DOWNLOADS_DIRECTORY, |
SeRya
2011/11/28 10:30:55
removableDirectoryEntry may be undefined. Access t
dgozman
2011/11/28 11:45:53
Done.
|
+ CD_NO_HISTORY); |
}; |
FileManager.prototype.setupPath_ = function(path) { |
@@ -1402,6 +1471,7 @@ |
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); |
@@ -1417,6 +1487,7 @@ |
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); |
@@ -1682,19 +1753,73 @@ |
FileManager.prototype.getLabelForRootPath_ = function(path) { |
SeRya
2011/11/28 10:30:55
Looks like meaning of the parameter has changed. N
dgozman
2011/11/28 11:45:53
Done.
|
// This hack lets us localize the top level directories. |
- if (path == 'Downloads') |
- return str('DOWNLOADS_DIRECTORY_LABEL'); |
+ if (path == DOWNLOADS_DIRECTORY) |
+ return str('CHROMEBOOK_DIRECTORY_LABEL'); |
- if (path == 'archive') |
+ if (path == ARCHIVE_DIRECTORY) |
return str('ARCHIVE_DIRECTORY_LABEL'); |
+ if (isParentPath(ARCHIVE_DIRECTORY, path)) |
+ return path.substring(ARCHIVE_DIRECTORY.length + 1); |
- if (path == 'removable') |
+ if (path == REMOVABLE_DIRECTORY) |
return str('REMOVABLE_DIRECTORY_LABEL'); |
+ if (isParentPath(REMOVABLE_DIRECTORY, path)) |
+ return path.substring(REMOVABLE_DIRECTORY.length + 1); |
return path || str('ROOT_DIRECTORY_LABEL'); |
SeRya
2011/11/28 10:30:55
path == '/', right?
dgozman
2011/11/28 11:45:53
Path may be arbitrary here. Changed to remove |pat
|
}; |
+ 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'; |
+ 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.setAttribute('src', this.getRootIconUrl_(entry.fullPath, false)); |
+ li.appendChild(icon); |
+ |
+ var div = this.document_.createElement('div'); |
+ div.textContent = this.getLabelForRootPath_(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); |
+ }; |
+ |
+ /** |
* Render the Name column of the detail table. |
* |
* Invoked by cr.ui.Table when a file needs to be rendered. |
@@ -2042,7 +2167,6 @@ |
// These are done in separate functions, as the checks require |
// asynchronous function calls. |
- this.maybeRenderUnmountTask_(selection); |
this.maybeRenderFormattingTask_(selection); |
}; |
@@ -2064,38 +2188,6 @@ |
}; |
/** |
- * 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. |
@@ -2176,44 +2268,49 @@ |
var self = this; |
chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { |
self.mountPoints_ = mountPoints; |
+ var changeDirectoryTo = null; |
+ |
if (event.eventType == 'mount') { |
- 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; |
- } |
+ // 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; |
} |
} |
+ 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)) { |
- self.changeDirectory(getParentPath(event.mountPath)); |
- return; |
+ changeDirectoryTo = getParentPath(event.mountPath); |
} |
- 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); |
+ // In the case of success, roots are changed and should be rescanned. |
+ if (event.status == 'success') |
+ self.updateRoots_(changeDirectoryTo); |
}); |
}; |
@@ -2232,10 +2329,6 @@ |
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]); |
@@ -2312,6 +2405,15 @@ |
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. |
*/ |
@@ -2319,23 +2421,45 @@ |
var bc = this.dialogDom_.querySelector('.breadcrumbs'); |
bc.innerHTML = ''; |
- var fullPath = this.currentDirEntry_.fullPath.replace(/\/$/, ''); |
- var pathNames = fullPath.split('/'); |
- var path = ''; |
+ 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('/') + '/'; |
+ |
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'; |
- if (i <= 1) { |
- // i == 0: root directory itself, i == 1: the files it contains. |
- div.textContent = this.getLabelForRootPath_(pathName); |
+ if (i == 0) { |
+ div.textContent = this.getLabelForRootPath_(path); |
SeRya
2011/11/28 10:30:55
Remove braces.
dgozman
2011/11/28 11:45:53
Done.
|
} else { |
div.textContent = pathName; |
} |
+ path = path + '/'; |
div.path = path; |
div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); |
@@ -2435,6 +2559,17 @@ |
} |
}; |
+ 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; |
+ } |
+ }; |
+ |
/** |
* Add the file/directory with given name to the current selection. |
* |
@@ -2550,7 +2685,17 @@ |
opt_saveHistory = !!opt_saveHistory; |
} |
- var location = '#' + encodeURI(dirEntry.fullPath); |
+ // 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 = '#' + encodeURI(dirEntry.fullPath); |
SeRya
2011/11/28 10:30:55
Uncomment.
dgozman
2011/11/28 11:45:53
Done.
|
if (opt_saveHistory) { |
history.pushState(undefined, dirEntry.fullPath, location); |
} else if (window.location.hash != location) { |
@@ -2560,7 +2705,7 @@ |
// window.location but doesn't change content of the ombibox. |
history.replaceState(undefined, dirEntry.fullPath, location); |
} |
- |
+*/ |
if (this.currentDirEntry_ && |
this.currentDirEntry_.fullPath == dirEntry.fullPath) { |
// Directory didn't actually change. |
@@ -2786,6 +2931,25 @@ |
} |
}; |
+ 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. |
* |
@@ -2800,8 +2964,12 @@ |
if (this.selection && |
this.selection.totalCount == 1 && |
- this.selection.entries[0].isFile) |
+ this.selection.entries[0].isFile && |
+ this.filenameInput_.value != this.selection.entries[0].name) { |
this.filenameInput_.value = this.selection.entries[0].name; |
+ if (this.params_.defaultPath == this.selection.entries[0].fullPath) |
+ this.selectDefaultPathInFilenameInput_(); |
+ } |
} |
this.updateOkButton_(); |
@@ -2954,9 +3122,7 @@ |
this.checkFreeSpace_(this.currentDirEntry_.fullPath); |
- // New folder should never be enabled in the root or media/ directories. |
- this.newFolderButton_.disabled = isSystemDirEntry(this.currentDirEntry_); |
- |
+ // TODO(dgozman): title may be better than this. |
this.document_.title = this.currentDirEntry_.fullPath; |
var self = this; |
@@ -3052,111 +3218,99 @@ |
this.currentList_.selectionModel.clear(); |
this.updateBreadcrumbs_(); |
+ this.updateRootsListSelection_(); |
- if (this.currentDirEntry_.fullPath != '/') { |
- // Add current request to pending result list |
- this.pendingRescanQueue_.push({ |
- onSuccess:opt_callback, |
- onError:opt_onError |
- }); |
+ // Add current request to pending result list |
+ this.pendingRescanQueue_.push({ |
+ onSuccess:opt_callback, |
+ onError:opt_onError |
+ }); |
- if (this.rescanRunning_) |
- return; |
+ if (this.rescanRunning_) |
+ return; |
- this.rescanRunning_ = true; |
+ 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_; |
+ // 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_ = []; |
+ this.pendingRescanQueue_ = []; |
- var self = this; |
- var reader; |
+ var self = this; |
+ var reader; |
- function onError() { |
+ 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].onError) |
+ try { |
+ callbacks[i].onError(); |
+ } catch (ex) { |
+ console.error('Caught exception while notifying about error: ' + |
+ name, ex); |
+ } |
+ } |
+ } |
+ |
+ function onReadSome(entries) { |
+ if (entries.length == 0) { |
+ metrics.recordTime('DirectoryScan'); |
+ if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) { |
+ metrics.reportCount("DownloadsCount", self.dataModel_.length); |
+ } |
+ |
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].onError) |
+ if (callbacks[i].onSuccess) |
try { |
- callbacks[i].onError(); |
+ callbacks[i].onSuccess(); |
} catch (ex) { |
console.error('Caught exception while notifying about error: ' + |
name, ex); |
} |
} |
+ |
+ return; |
} |
- function onReadSome(entries) { |
- if (entries.length == 0) { |
- metrics.recordTime('DirectoryScan'); |
- if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) { |
- metrics.reportCount("DownloadsCount", self.dataModel_.length); |
- } |
+ // 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); |
- if (self.pendingRescanQueue_.length > 0) { |
- setTimeout(self.rescanDirectory_.bind(self), |
- SIMULTANEOUS_RESCAN_INTERVAL); |
- } |
+ // 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) != '.'; |
+ }); |
+ } |
- 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); |
- } |
- } |
+ spliceArgs.unshift(0, 0); // index, deleteCount |
+ self.dataModel_.splice.apply(self.dataModel_, spliceArgs); |
- 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) != '.'; |
- }); |
- } |
- |
- spliceArgs.unshift(0, 0); // index, deleteCount |
- self.dataModel_.splice.apply(self.dataModel_, spliceArgs); |
- |
- metrics.startInterval('DirectoryScan'); |
- |
- // Keep reading until entries.length is 0. |
- reader.readEntries(onReadSome, onError); |
- }; |
- |
- // If not the root directory, just read the contents. |
- reader = this.currentDirEntry_.createReader(); |
+ // Keep reading until entries.length is 0. |
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); |
+ metrics.startInterval('DirectoryScan'); |
- if (opt_callback) |
- opt_callback(); |
+ // If not the root directory, just read the contents. |
+ reader = this.currentDirEntry_.createReader(); |
+ reader.readEntries(onReadSome, onError); |
}; |
FileManager.prototype.findListItem_ = function(event) { |
@@ -3400,7 +3554,16 @@ |
}, 0); |
}; |
- FileManager.prototype.onNewFolderButtonClick_ = function(event) { |
+ FileManager.prototype.onToggleSidebar_ = function(event) { |
+ if (this.dialogContainer_.hasAttribute('sidebar')) { |
SeRya
2011/11/28 10:30:55
Now we have 3 attributes that does essentially the
dgozman
2011/11/28 11:45:53
I've filed a bug: crosbug.com/23455.
|
+ this.dialogContainer_.removeAttribute('sidebar'); |
+ } else { |
+ this.dialogContainer_.setAttribute('sidebar', 'sidebar'); |
+ } |
+ setTimeout(this.onResize_.bind(this), 300); |
+ }; |
+ |
+ FileManager.prototype.onNewFolderCommand_ = function(event) { |
var self = this; |
function onNameSelected(name) { |
@@ -3529,9 +3692,10 @@ |
break; |
case 32: // Ctrl-Space => New Folder. |
- if (this.newFolderButton_.style.display != 'none' && event.ctrlKey) { |
+ if ((this.dialogType_ == 'saveas-file' || |
+ this.dialogType_ == 'full-page') && event.ctrlKey) { |
event.preventDefault(); |
- this.onNewFolderButtonClick_(); |
+ this.onNewFolderCommand_(); |
} |
break; |