Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * FileManager constructor. | 6 * FileManager constructor. |
| 7 * | 7 * |
| 8 * FileManager objects encapsulate the functionality of the file selector | 8 * FileManager objects encapsulate the functionality of the file selector |
| 9 * dialogs, as well as the full screen file manager application (though the | 9 * dialogs, as well as the full screen file manager application (though the |
| 10 * latter is not yet implemented). | 10 * latter is not yet implemented). |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, | 46 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, |
| 47 FileManager.DialogType.FULL_PAGE]); | 47 FileManager.DialogType.FULL_PAGE]); |
| 48 | 48 |
| 49 // TODO(dgozman): This will be changed to LocaleInfo. | 49 // TODO(dgozman): This will be changed to LocaleInfo. |
| 50 this.locale_ = new v8Locale(navigator.language); | 50 this.locale_ = new v8Locale(navigator.language); |
| 51 | 51 |
| 52 this.initFileSystem_(); | 52 this.initFileSystem_(); |
| 53 this.initDom_(); | 53 this.initDom_(); |
| 54 this.initDialogType_(); | 54 this.initDialogType_(); |
| 55 this.dialogDom_.style.opacity = '1'; | 55 this.dialogDom_.style.opacity = '1'; |
| 56 | |
| 57 this.lastNonGDataSearchPath_ = null; | |
| 56 } | 58 } |
| 57 | 59 |
| 58 FileManager.prototype = { | 60 FileManager.prototype = { |
| 59 __proto__: cr.EventTarget.prototype | 61 __proto__: cr.EventTarget.prototype |
| 60 }; | 62 }; |
| 61 | 63 |
| 62 // Anonymous "namespace". | 64 // Anonymous "namespace". |
| 63 (function() { | 65 (function() { |
| 64 | 66 |
| 65 // Private variables and helper functions. | 67 // Private variables and helper functions. |
| (...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 971 this.commands_[key].disabled = !this.canExecute_(key); | 973 this.commands_[key].disabled = !this.canExecute_(key); |
| 972 }; | 974 }; |
| 973 | 975 |
| 974 /** | 976 /** |
| 975 * @param {string} commandId Command identifier. | 977 * @param {string} commandId Command identifier. |
| 976 * @return {boolean} True if the command can be executed for current | 978 * @return {boolean} True if the command can be executed for current |
| 977 * selection. | 979 * selection. |
| 978 */ | 980 */ |
| 979 FileManager.prototype.canExecute_ = function(commandId) { | 981 FileManager.prototype.canExecute_ = function(commandId) { |
| 980 var readonly = this.isOnReadonlyDirectory(); | 982 var readonly = this.isOnReadonlyDirectory(); |
| 983 var shouldCreate = !util.isSpecialReadonlyDirectory( | |
| 984 this.directoryModel_.getCurrentDirEntry().fullPath); | |
| 981 switch (commandId) { | 985 switch (commandId) { |
| 982 case 'copy': | 986 case 'copy': |
| 983 case 'cut': | 987 case 'cut': |
| 984 return this.document_.queryCommandEnabled(commandId); | 988 return this.document_.queryCommandEnabled(commandId); |
| 985 | 989 |
| 986 case 'paste': | 990 case 'paste': |
| 987 return !!this.fileTransferController_ && | 991 return !!this.fileTransferController_ && |
| 988 this.fileTransferController_.queryPasteCommandEnabled(); | 992 this.fileTransferController_.queryPasteCommandEnabled() && |
|
SeRya
2012/05/04 10:26:17
What about dropping files into the search results?
tbarzic
2012/05/05 00:56:06
Done.
| |
| 993 shouldCreate; | |
| 989 | 994 |
| 990 case 'rename': | 995 case 'rename': |
| 991 return (// Initialized to the point where we have a current directory | 996 return (// Initialized to the point where we have a current directory |
| 992 !readonly && | 997 !readonly && |
| 993 // Rename not in progress. | 998 // Rename not in progress. |
| 994 !this.isRenamingInProgress() && | 999 !this.isRenamingInProgress() && |
| 995 // Only one file selected. | 1000 // Only one file selected. |
| 996 this.selection && | 1001 this.selection && |
| 997 this.selection.totalCount == 1); | 1002 this.selection.totalCount == 1); |
| 998 | 1003 |
| 999 case 'delete': | 1004 case 'delete': |
| 1000 return (// Initialized to the point where we have a current directory | 1005 return (// Initialized to the point where we have a current directory |
| 1001 !readonly && | 1006 !readonly && |
| 1002 // Rename not in progress. | 1007 // Rename not in progress. |
| 1003 !this.isRenamingInProgress() && | 1008 !this.isRenamingInProgress() && |
| 1004 this.selection && | 1009 this.selection && |
| 1005 this.selection.totalCount > 0); | 1010 this.selection.totalCount > 0); |
| 1006 | 1011 |
| 1007 case 'newfolder': | 1012 case 'newfolder': |
| 1008 return !readonly && | 1013 return !readonly && |
| 1014 shouldCreate && | |
| 1009 (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE || | 1015 (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE || |
| 1010 this.dialogType_ == FileManager.DialogType.FULL_PAGE); | 1016 this.dialogType_ == FileManager.DialogType.FULL_PAGE); |
| 1011 | 1017 |
| 1012 case 'unmount': | 1018 case 'unmount': |
| 1013 return true; | 1019 return true; |
| 1014 | 1020 |
| 1015 case 'format': | 1021 case 'format': |
| 1016 var entry = this.directoryModel_.getCurrentRootDirEntry(); | 1022 var entry = this.directoryModel_.getCurrentRootDirEntry(); |
| 1017 | 1023 |
| 1018 return entry && DirectoryModel.getRootType(entry.fullPath) == | 1024 return entry && DirectoryModel.getRootType(entry.fullPath) == |
| (...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1823 * Render filename label for grid and list view. | 1829 * Render filename label for grid and list view. |
| 1824 * @param {Entry} entry The Entry object to render. | 1830 * @param {Entry} entry The Entry object to render. |
| 1825 * @return {HTMLDivElement} The label. | 1831 * @return {HTMLDivElement} The label. |
| 1826 */ | 1832 */ |
| 1827 FileManager.prototype.renderFileNameLabel_ = function(entry) { | 1833 FileManager.prototype.renderFileNameLabel_ = function(entry) { |
| 1828 // Filename need to be in a '.filename-label' container for correct | 1834 // Filename need to be in a '.filename-label' container for correct |
| 1829 // work of inplace renaming. | 1835 // work of inplace renaming. |
| 1830 var fileName = this.document_.createElement('div'); | 1836 var fileName = this.document_.createElement('div'); |
| 1831 fileName.className = 'filename-label'; | 1837 fileName.className = 'filename-label'; |
| 1832 | 1838 |
| 1839 // If the entry is gdata search result, we should calculate name to use | |
| 1840 // instead of using |entry.name|. | |
| 1841 var gdataSearchResult = | |
| 1842 util.getFileAndDisplayNameForGDataSearchResult(entry.fullPath); | |
| 1843 var displayName = gdataSearchResult ? gdataSearchResult.displayName : | |
| 1844 entry.name; | |
| 1845 | |
| 1833 fileName.textContent = | 1846 fileName.textContent = |
| 1834 this.directoryModel_.getCurrentDirEntry().name == '' ? | 1847 this.directoryModel_.getCurrentDirEntry().name == '' ? |
| 1835 this.getRootLabel_(entry.name) : entry.name; | 1848 this.getRootLabel_(displayName) : displayName; |
| 1836 return fileName; | 1849 return fileName; |
| 1837 }; | 1850 }; |
| 1838 | 1851 |
| 1839 /** | 1852 /** |
| 1840 * Render the Size column of the detail table. | 1853 * Render the Size column of the detail table. |
| 1841 * | 1854 * |
| 1842 * @param {Entry} entry The Entry object to render. | 1855 * @param {Entry} entry The Entry object to render. |
| 1843 * @param {string} columnId The id of the column to be rendered. | 1856 * @param {string} columnId The id of the column to be rendered. |
| 1844 * @param {cr.ui.Table} table The table doing the rendering. | 1857 * @param {cr.ui.Table} table The table doing the rendering. |
| 1845 */ | 1858 */ |
| (...skipping 1017 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2863 div.textContent = i == 0 ? this.getRootLabel_(path) : pathName; | 2876 div.textContent = i == 0 ? this.getRootLabel_(path) : pathName; |
| 2864 | 2877 |
| 2865 path = path + '/'; | 2878 path = path + '/'; |
| 2866 div.path = path; | 2879 div.path = path; |
| 2867 | 2880 |
| 2868 bc.appendChild(div); | 2881 bc.appendChild(div); |
| 2869 | 2882 |
| 2870 if (i == pathNames.length - 1) { | 2883 if (i == pathNames.length - 1) { |
| 2871 div.classList.add('breadcrumb-last'); | 2884 div.classList.add('breadcrumb-last'); |
| 2872 } else { | 2885 } else { |
| 2873 div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); | 2886 // This is virtual, inaccessible directory. |
| 2887 if (path == util.GDATA_SEARCH_ROOT_PATH) { | |
| 2888 div.classList.add('breadcrumb-last'); | |
|
SeRya
2012/05/04 10:26:17
breadcrumb-last in the middle of the path looks st
tbarzic
2012/05/05 00:56:06
Done
| |
| 2889 } else { | |
| 2890 div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); | |
| 2891 } | |
| 2874 | 2892 |
| 2875 var spacer = doc.createElement('div'); | 2893 var spacer = doc.createElement('div'); |
| 2876 spacer.className = 'separator'; | 2894 spacer.className = 'separator'; |
| 2877 bc.appendChild(spacer); | 2895 bc.appendChild(spacer); |
| 2878 } | 2896 } |
| 2879 } | 2897 } |
| 2880 this.truncateBreadcrumbs_(); | 2898 this.truncateBreadcrumbs_(); |
| 2881 }; | 2899 }; |
| 2882 | 2900 |
| 2883 FileManager.prototype.isRenamingInProgress = function() { | 2901 FileManager.prototype.isRenamingInProgress = function() { |
| (...skipping 649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3533 }; | 3551 }; |
| 3534 | 3552 |
| 3535 FileManager.prototype.onRenameInputBlur_ = function(event) { | 3553 FileManager.prototype.onRenameInputBlur_ = function(event) { |
| 3536 if (this.isRenamingInProgress() && !this.renameInput_.validation_) | 3554 if (this.isRenamingInProgress() && !this.renameInput_.validation_) |
| 3537 this.commitRename_(); | 3555 this.commitRename_(); |
| 3538 }; | 3556 }; |
| 3539 | 3557 |
| 3540 FileManager.prototype.commitRename_ = function() { | 3558 FileManager.prototype.commitRename_ = function() { |
| 3541 var input = this.renameInput_; | 3559 var input = this.renameInput_; |
| 3542 var entry = input.currentEntry; | 3560 var entry = input.currentEntry; |
| 3543 var newName = input.value; | 3561 var newNameInput = input.value; |
| 3562 | |
| 3563 // If we are renaming gdata search result, we'll have to format newName we | |
| 3564 // use in file system operations like: <resource_id>.<file_name>. | |
| 3565 var searchResultName = | |
| 3566 util.getFileAndDisplayNameForGDataSearchResult(entry.fullPath); | |
| 3567 | |
| 3568 var newName = | |
| 3569 searchResultName ? searchResultName.resourceId + '.' + newNameInput : | |
| 3570 newNameInput; | |
| 3571 var oldName = searchResultName ? searchResultName.displayName : entry.name; | |
| 3544 | 3572 |
| 3545 if (newName == entry.name) { | 3573 if (newName == entry.name) { |
| 3546 this.cancelRename_(); | 3574 this.cancelRename_(); |
| 3547 return; | 3575 return; |
| 3548 } | 3576 } |
| 3549 | 3577 |
| 3550 var nameNode = this.findListItemForNode_(this.renameInput_). | 3578 var nameNode = this.findListItemForNode_(this.renameInput_). |
| 3551 querySelector('.filename-label'); | 3579 querySelector('.filename-label'); |
| 3552 | 3580 |
| 3553 input.validation_ = true; | 3581 input.validation_ = true; |
| 3554 function validationDone() { | 3582 function validationDone() { |
| 3555 input.validation_ = false; | 3583 input.validation_ = false; |
| 3556 // Alert dialog restores focus unless the item removed from DOM. | 3584 // Alert dialog restores focus unless the item removed from DOM. |
| 3557 if (this.document_.activeElement != input) | 3585 if (this.document_.activeElement != input) |
| 3558 this.cancelRename_(); | 3586 this.cancelRename_(); |
| 3559 } | 3587 } |
| 3560 | 3588 |
| 3561 if (!this.validateFileName_(newName, validationDone.bind(this))) | 3589 if (!this.validateFileName_(newNameInput, validationDone.bind(this))) |
| 3562 return; | 3590 return; |
| 3563 | 3591 |
| 3564 function onError(err) { | 3592 function onError(err) { |
| 3565 nameNode.textContent = entry.name; | 3593 nameNode.textContent = entry.name; |
| 3566 this.alert.show(strf('ERROR_RENAMING', entry.name, | 3594 this.alert.show(strf('ERROR_RENAMING', entry.name, |
| 3567 util.getFileErrorMnemonic(err.code))); | 3595 util.getFileErrorMnemonic(err.code))); |
| 3568 } | 3596 } |
| 3569 | 3597 |
| 3570 this.cancelRename_(); | 3598 this.cancelRename_(); |
| 3571 // Optimistically apply new name immediately to avoid flickering in | 3599 // Optimistically apply new name immediately to avoid flickering in |
| 3572 // case of success. | 3600 // case of success. |
| 3573 nameNode.textContent = newName; | 3601 nameNode.textContent = newNameInput; |
| 3574 | 3602 |
| 3575 this.directoryModel_.doesExist(newName, function(exists, isFile) { | 3603 this.directoryModel_.doesExist(newName, function(exists, isFile) { |
|
SeRya
2012/05/04 10:26:17
I'd suggest to isolate the UI from knowlage about
tbarzic
2012/05/05 00:56:06
Really good point, that's much cleaner :)
| |
| 3576 if (!exists) { | 3604 if (!exists) { |
| 3577 this.directoryModel_.renameEntry(entry, newName, onError.bind(this)); | 3605 this.directoryModel_.renameEntry(entry, newName, onError.bind(this)); |
| 3578 } else { | 3606 } else { |
| 3579 nameNode.textContent = entry.name; | 3607 nameNode.textContent = oldName; |
| 3580 var message = isFile ? 'FILE_ALREADY_EXISTS' : | 3608 var message = isFile ? 'FILE_ALREADY_EXISTS' : |
| 3581 'DIRECTORY_ALREADY_EXISTS'; | 3609 'DIRECTORY_ALREADY_EXISTS'; |
| 3582 this.alert.show(strf(message, newName)); | 3610 this.alert.show(strf(message, newNameInput)); |
| 3583 } | 3611 } |
| 3584 }.bind(this)); | 3612 }.bind(this)); |
| 3585 }; | 3613 }; |
| 3586 | 3614 |
| 3587 FileManager.prototype.cancelRename_ = function() { | 3615 FileManager.prototype.cancelRename_ = function() { |
| 3588 this.renameInput_.currentEntry = null; | 3616 this.renameInput_.currentEntry = null; |
| 3589 | 3617 |
| 3590 var parent = this.renameInput_.parentNode; | 3618 var parent = this.renameInput_.parentNode; |
| 3591 if (parent) { | 3619 if (parent) { |
| 3592 parent.removeAttribute('renaming'); | 3620 parent.removeAttribute('renaming'); |
| (...skipping 663 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4256 if (oldValue) { | 4284 if (oldValue) { |
| 4257 event.target.removeAttribute('checked'); | 4285 event.target.removeAttribute('checked'); |
| 4258 } else { | 4286 } else { |
| 4259 event.target.setAttribute('checked', 'checked'); | 4287 event.target.setAttribute('checked', 'checked'); |
| 4260 } | 4288 } |
| 4261 }; | 4289 }; |
| 4262 | 4290 |
| 4263 FileManager.prototype.onSearchBoxUpdate_ = function(event) { | 4291 FileManager.prototype.onSearchBoxUpdate_ = function(event) { |
| 4264 var searchString = this.dialogDom_.querySelector('#search-box').value; | 4292 var searchString = this.dialogDom_.querySelector('#search-box').value; |
| 4265 if (searchString) { | 4293 if (searchString) { |
| 4266 this.directoryModel_.addFilter( | 4294 if (!this.isOnGData()) { |
|
SeRya
2012/05/04 10:26:17
I think this is too low level logic. It should be
tbarzic
2012/05/05 00:56:06
Done.
| |
| 4267 'searchbox', | 4295 this.directoryModel_.addFilter( |
| 4268 function(e) { | 4296 'searchbox', |
| 4269 return e.name.substr(0, searchString.length) == searchString; | 4297 function(e) { |
| 4270 }); | 4298 return e.name.substr(0, searchString.length) == searchString; |
| 4299 }); | |
| 4300 } else { | |
| 4301 // If current path is not under gdata search dir, remeber it, so we can | |
| 4302 // navigate to it when we exit search mode. | |
| 4303 var currentDirPath = this.directoryModel_.getCurrentDirEntry().fullPath; | |
| 4304 if (currentDirPath.search(util.GDATA_SEARCH_ROOT_PATH) != 0) | |
| 4305 this.lastNonGDataSearchPath_ = currentDirPath; | |
| 4306 | |
| 4307 this.directoryModel_.changeDirectory( | |
|
SeRya
2012/05/04 10:26:17
changeDirectory causes putting the new directory i
tbarzic
2012/05/05 00:56:06
Done.
| |
| 4308 util.createGDataSearchPath(searchString)); | |
| 4309 } | |
| 4271 } else { | 4310 } else { |
| 4272 this.directoryModel_.removeFilter('searchbox'); | 4311 if (!this.isOnGData()) { |
| 4312 this.directoryModel_.removeFilter('searchbox'); | |
| 4313 } else { | |
| 4314 // Go to last known non gdata search directory. | |
| 4315 var newDirectory = this.lastNonGDataSearchPath_ || | |
| 4316 '/' + DirectoryModel.GDATA_DIRECTORY; | |
|
SeRya
2012/05/04 10:26:17
You set GData root even if search started in a sub
tbarzic
2012/05/05 00:56:06
are you sure? What am I missing?
| |
| 4317 this.lastNonGDataSearchPath_ = null; | |
| 4318 this.directoryModel_.changeDirectory(newDirectory); | |
| 4319 } | |
| 4273 } | 4320 } |
| 4274 }; | 4321 }; |
| 4275 | 4322 |
| 4276 FileManager.prototype.decorateSplitter = function(splitterElement) { | 4323 FileManager.prototype.decorateSplitter = function(splitterElement) { |
| 4277 var self = this; | 4324 var self = this; |
| 4278 | 4325 |
| 4279 var Splitter = cr.ui.Splitter; | 4326 var Splitter = cr.ui.Splitter; |
| 4280 | 4327 |
| 4281 var customSplitter = cr.ui.define('div'); | 4328 var customSplitter = cr.ui.define('div'); |
| 4282 | 4329 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4397 | 4444 |
| 4398 this.directoryModel_.addEventListener('scan-completed', maybeShowBanner); | 4445 this.directoryModel_.addEventListener('scan-completed', maybeShowBanner); |
| 4399 this.directoryModel_.addEventListener('rescan-completed', maybeShowBanner); | 4446 this.directoryModel_.addEventListener('rescan-completed', maybeShowBanner); |
| 4400 | 4447 |
| 4401 var style = this.document_.createElement('link'); | 4448 var style = this.document_.createElement('link'); |
| 4402 style.rel = 'stylesheet'; | 4449 style.rel = 'stylesheet'; |
| 4403 style.href = 'css/gdrive_welcome.css'; | 4450 style.href = 'css/gdrive_welcome.css'; |
| 4404 this.document_.head.appendChild(style); | 4451 this.document_.head.appendChild(style); |
| 4405 }; | 4452 }; |
| 4406 })(); | 4453 })(); |
| OLD | NEW |