OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 // Setting the src of an img to an empty string can crash the browser, so we | 5 // Setting the src of an img to an empty string can crash the browser, so we |
6 // use an empty 1x1 gif instead. | 6 // use an empty 1x1 gif instead. |
7 const EMPTY_IMAGE_URI = 'data:image/gif;base64,' | 7 const EMPTY_IMAGE_URI = 'data:image/gif;base64,' |
8 + 'R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D'; | 8 + 'R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D'; |
9 | 9 |
10 var g_slideshow_data = null; | 10 var g_slideshow_data = null; |
(...skipping 13 matching lines...) Expand all Loading... |
24 * the root filesystem for the new FileManager. | 24 * the root filesystem for the new FileManager. |
25 * @param {Object} params A map of parameter names to values controlling the | 25 * @param {Object} params A map of parameter names to values controlling the |
26 * appearance of the FileManager. Names are: | 26 * appearance of the FileManager. Names are: |
27 * - type: A value from FileManager.DialogType defining what kind of | 27 * - type: A value from FileManager.DialogType defining what kind of |
28 * dialog to present. Defaults to FULL_PAGE. | 28 * dialog to present. Defaults to FULL_PAGE. |
29 * - title: The title for the dialog. Defaults to a localized string based | 29 * - title: The title for the dialog. Defaults to a localized string based |
30 * on the dialog type. | 30 * on the dialog type. |
31 * - defaultPath: The default path for the dialog. The default path should | 31 * - defaultPath: The default path for the dialog. The default path should |
32 * end with a trailing slash if it represents a directory. | 32 * end with a trailing slash if it represents a directory. |
33 */ | 33 */ |
34 function FileManager(dialogDom, filesystem, rootEntries) { | 34 function FileManager(dialogDom, filesystem, rootEntries, params) { |
35 console.log('Init FileManager: ' + dialogDom); | 35 console.log('Init FileManager: ' + dialogDom); |
36 | 36 |
37 this.dialogDom_ = dialogDom; | 37 this.dialogDom_ = dialogDom; |
38 this.rootEntries_ = rootEntries; | 38 this.rootEntries_ = rootEntries; |
39 this.filesystem_ = filesystem; | 39 this.filesystem_ = filesystem; |
40 this.params_ = location.search ? | 40 this.params_ = params || {}; |
41 JSON.parse(decodeURIComponent(location.search.substr(1))) : | |
42 {}; | |
43 | 41 |
44 this.listType_ = null; | 42 this.listType_ = null; |
45 | 43 |
46 this.metadataCache_ = {}; | 44 this.metadataCache_ = {}; |
47 | 45 |
48 this.selection = null; | 46 this.selection = null; |
49 | 47 |
50 this.clipboard_ = null; // Current clipboard, or null if empty. | 48 this.clipboard_ = null; // Current clipboard, or null if empty. |
51 | 49 |
52 this.butterTimer_ = null; | 50 this.butterTimer_ = null; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { | 125 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { |
128 self.mountPoints_ = mountPoints; | 126 self.mountPoints_ = mountPoints; |
129 }); | 127 }); |
130 | 128 |
131 chrome.fileBrowserHandler.onExecute.addListener( | 129 chrome.fileBrowserHandler.onExecute.addListener( |
132 this.onFileTaskExecute_.bind(this)); | 130 this.onFileTaskExecute_.bind(this)); |
133 | 131 |
134 this.initCommands_(); | 132 this.initCommands_(); |
135 this.initDom_(); | 133 this.initDom_(); |
136 this.initDialogType_(); | 134 this.initDialogType_(); |
137 this.setupCurrentDirectory_(); | 135 this.initDefaultDirectory_(this.params_.defaultPath); |
138 | 136 |
139 this.summarizeSelection_(); | 137 this.summarizeSelection_(); |
140 this.updatePreview_(); | 138 this.updatePreview_(); |
141 | 139 |
142 chrome.fileBrowserPrivate.onDiskChanged.addListener( | 140 chrome.fileBrowserPrivate.onDiskChanged.addListener( |
143 this.onDiskChanged_.bind(this)); | 141 this.onDiskChanged_.bind(this)); |
144 | 142 |
145 this.refocus(); | 143 this.refocus(); |
146 | 144 |
147 // Pass all URLs to the metadata reader until we have a correct filter. | 145 // Pass all URLs to the metadata reader until we have a correct filter. |
(...skipping 643 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 this.pasteButton_.disabled = !event.canExecute; | 789 this.pasteButton_.disabled = !event.canExecute; |
792 break; | 790 break; |
793 | 791 |
794 case 'rename': | 792 case 'rename': |
795 event.canExecute = | 793 event.canExecute = |
796 (// Initialized to the point where we have a current directory | 794 (// Initialized to the point where we have a current directory |
797 this.currentDirEntry_ && | 795 this.currentDirEntry_ && |
798 // Rename not in progress. | 796 // Rename not in progress. |
799 !this.renameInput_.currentEntry && | 797 !this.renameInput_.currentEntry && |
800 // Only one file selected. | 798 // Only one file selected. |
801 this.selection && | |
802 this.selection.totalCount == 1 && | 799 this.selection.totalCount == 1 && |
803 !isSystemDirEntry(this.currentDirEntry_)); | 800 !isSystemDirEntry(this.currentDirEntry_)); |
804 break; | 801 break; |
805 | 802 |
806 case 'delete': | 803 case 'delete': |
807 event.canExecute = | 804 event.canExecute = |
808 (// Initialized to the point where we have a current directory | 805 (// Initialized to the point where we have a current directory |
809 this.currentDirEntry_ && | 806 this.currentDirEntry_ && |
810 // Rename not in progress. | 807 // Rename not in progress. |
811 !this.renameInput_.currentEntry && | 808 !this.renameInput_.currentEntry && |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
994 this.initiateRename_(label); | 991 this.initiateRename_(label); |
995 return; | 992 return; |
996 | 993 |
997 case 'delete': | 994 case 'delete': |
998 this.deleteEntries(this.selection.entries); | 995 this.deleteEntries(this.selection.entries); |
999 return; | 996 return; |
1000 } | 997 } |
1001 }; | 998 }; |
1002 | 999 |
1003 /** | 1000 /** |
1004 * Respond to the back and forward buttons. | 1001 * Respond to the back button. |
1005 */ | 1002 */ |
1006 FileManager.prototype.onPopState_ = function(event) { | 1003 FileManager.prototype.onPopState_ = function(event) { |
1007 // TODO(serya): We should restore selected items here. | 1004 this.changeDirectory(event.state, CD_NO_HISTORY); |
1008 this.setupCurrentDirectory_(); | |
1009 }; | 1005 }; |
1010 | 1006 |
1011 /** | 1007 /** |
1012 * Resize details and thumb views to fit the new window size. | 1008 * Resize details and thumb views to fit the new window size. |
1013 */ | 1009 */ |
1014 FileManager.prototype.onResize_ = function() { | 1010 FileManager.prototype.onResize_ = function() { |
1015 this.table_.style.height = this.grid_.style.height = | 1011 this.table_.style.height = this.grid_.style.height = |
1016 this.grid_.parentNode.clientHeight + 'px'; | 1012 this.grid_.parentNode.clientHeight + 'px'; |
1017 this.table_.style.width = this.grid_.style.width = | 1013 this.table_.style.width = this.grid_.style.width = |
1018 this.grid_.parentNode.clientWidth + 'px'; | 1014 this.grid_.parentNode.clientWidth + 'px'; |
(...skipping 12 matching lines...) Expand all Loading... |
1031 this.currentList_.redraw(); | 1027 this.currentList_.redraw(); |
1032 } | 1028 } |
1033 }; | 1029 }; |
1034 | 1030 |
1035 FileManager.prototype.resolvePath = function( | 1031 FileManager.prototype.resolvePath = function( |
1036 path, resultCallback, errorCallback) { | 1032 path, resultCallback, errorCallback) { |
1037 return util.resolvePath(this.filesystem_.root, path, resultCallback, | 1033 return util.resolvePath(this.filesystem_.root, path, resultCallback, |
1038 errorCallback); | 1034 errorCallback); |
1039 }; | 1035 }; |
1040 | 1036 |
1041 /** | 1037 FileManager.prototype.initDefaultDirectory_ = function(path) { |
1042 * Restores current directory and may be a selected item after page load (or | 1038 if (!path) { |
1043 * reload) or popping a state (after click on back/forward). If location.hash | 1039 // No preset given, find a good place to start. |
1044 * is present it means that the user has navigated somewhere and that place | 1040 // Check for removable devices, if there are none, go to Downloads. |
1045 * will be restored. defaultPath primarily is used with save/open dialogs. | 1041 for (var i = 0; i != this.rootEntries_.length; i++) { |
1046 * Default path may also contain a file name. Freshly opened file manager | 1042 var rootEntry = this.rootEntries_[i]; |
1047 * window has neither. | 1043 if (rootEntry.fullPath == REMOVABLE_DIRECTORY) { |
1048 */ | 1044 var foundRemovable = false; |
1049 FileManager.prototype.setupCurrentDirectory_ = function() { | 1045 var self = this; |
1050 if (location.hash) { | 1046 util.forEachDirEntry(rootEntry, function(result) { |
1051 // Location hash has the highest priority. | 1047 if (result) { |
1052 var path = decodeURI(location.hash.substr(1)); | 1048 foundRemovable = true; |
1053 this.changeDirectory(path, CD_NO_HISTORY); | 1049 } else { // Done enumerating, and we know the answer. |
1054 return; | 1050 self.initDefaultDirectory_( |
1055 } else if (this.params_.defaultPath) { | 1051 foundRemovable ? '/' : DOWNLOADS_DIRECTORY); |
1056 this.setupPath_(this.params_.defaultPath); | 1052 } |
1057 } else { | 1053 }); |
1058 this.setupDefaultPath_(); | 1054 return; |
1059 } | 1055 } |
1060 }; | 1056 } |
1061 | 1057 |
1062 FileManager.prototype.setupDefaultPath_ = function() { | 1058 // Removable root directory is missing altogether. |
1063 // No preset given, find a good place to start. | 1059 path = DOWNLOADS_DIRECTORY; |
1064 // Check for removable devices, if there are none, go to Downloads. | |
1065 var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) { | |
1066 return rootEntry.fullPath == REMOVABLE_DIRECTORY; | |
1067 })[0]; | |
1068 if (!removableDirectoryEntry) { | |
1069 this.changeDirectory(DOWNLOADS_DIRECTORY, CD_NO_HISTORY); | |
1070 return; | |
1071 } | 1060 } |
1072 | 1061 |
1073 var foundRemovable = false; | |
1074 util.forEachDirEntry(removableDirectoryEntry, function(result) { | |
1075 if (result) { | |
1076 foundRemovable = true; | |
1077 } else { // Done enumerating, and we know the answer. | |
1078 this.changeDirectory(foundRemovable ? '/' : DOWNLOADS_DIRECTORY, | |
1079 CD_NO_HISTORY); | |
1080 } | |
1081 }.bind(this)); | |
1082 }; | |
1083 | |
1084 FileManager.prototype.setupPath_ = function(path) { | |
1085 // Split the dirname from the basename. | 1062 // Split the dirname from the basename. |
1086 var ary = path.match(/^(.*?)(?:\/([^\/]+))?$/); | 1063 var ary = path.match(/^(.*?)(?:\/([^\/]+))?$/); |
1087 if (!ary) { | 1064 if (!ary) { |
1088 console.warn('Unable to split default path: ' + path); | 1065 console.warn('Unable to split default path: ' + path); |
1089 self.changeDirectory('/', CD_NO_HISTORY); | 1066 self.changeDirectory('/', CD_NO_HISTORY); |
1090 return; | 1067 return; |
1091 } | 1068 } |
1092 | 1069 |
1093 var baseName = ary[1]; | 1070 var baseName = ary[1]; |
1094 var leafName = ary[2]; | 1071 var leafName = ary[2]; |
(...skipping 907 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2002 * | 1979 * |
2003 * @param {string} path The absolute path to the new directory. | 1980 * @param {string} path The absolute path to the new directory. |
2004 * @param {bool} opt_saveHistory Save this in the history stack (defaults | 1981 * @param {bool} opt_saveHistory Save this in the history stack (defaults |
2005 * to true). | 1982 * to true). |
2006 * @param {string} opt_selectedEntry The name of the file to select after | 1983 * @param {string} opt_selectedEntry The name of the file to select after |
2007 * changing directories. | 1984 * changing directories. |
2008 */ | 1985 */ |
2009 FileManager.prototype.changeDirectoryEntry = function(dirEntry, | 1986 FileManager.prototype.changeDirectoryEntry = function(dirEntry, |
2010 opt_saveHistory, | 1987 opt_saveHistory, |
2011 opt_selectedEntry) { | 1988 opt_selectedEntry) { |
2012 if (typeof opt_saveHistory == 'undefined') { | |
2013 opt_saveHistory = true; | |
2014 } else { | |
2015 opt_saveHistory = !!opt_saveHistory; | |
2016 } | |
2017 | |
2018 var location = '#' + encodeURI(dirEntry.fullPath); | |
2019 if (opt_saveHistory) { | |
2020 history.pushState(undefined, dirEntry.fullPath, location); | |
2021 } else if (window.location.hash != location) { | |
2022 // If the user typed URL manually that is not canonical it would be fixed | |
2023 // here. However it seems history.replaceState doesn't work properly | |
2024 // with rewritable URLs (while does with history.pushState). It changes | |
2025 // window.location but doesn't change content of the ombibox. | |
2026 history.replaceState(undefined, dirEntry.fullPath, location); | |
2027 } | |
2028 | |
2029 if (this.currentDirEntry_ && | 1989 if (this.currentDirEntry_ && |
2030 this.currentDirEntry_.fullPath == dirEntry.fullPath) { | 1990 this.currentDirEntry_.fullPath == dirEntry.fullPath) { |
2031 // Directory didn't actually change. | 1991 // Directory didn't actually change. |
2032 if (opt_selectedEntry) | 1992 if (opt_selectedEntry) |
2033 this.selectEntry(opt_selectedEntry); | 1993 this.selectEntry(opt_selectedEntry); |
2034 return; | 1994 return; |
2035 } | 1995 } |
2036 | 1996 |
| 1997 if (typeof opt_saveHistory == 'undefined') { |
| 1998 opt_saveHistory = true; |
| 1999 } else { |
| 2000 opt_saveHistory = !!opt_saveHistory; |
| 2001 } |
| 2002 |
2037 var e = new cr.Event('directory-changed'); | 2003 var e = new cr.Event('directory-changed'); |
2038 e.previousDirEntry = this.currentDirEntry_; | 2004 e.previousDirEntry = this.currentDirEntry_; |
2039 e.newDirEntry = dirEntry; | 2005 e.newDirEntry = dirEntry; |
2040 e.saveHistory = opt_saveHistory; | 2006 e.saveHistory = opt_saveHistory; |
2041 e.selectedEntry = opt_selectedEntry; | 2007 e.selectedEntry = opt_selectedEntry; |
2042 this.currentDirEntry_ = dirEntry; | 2008 this.currentDirEntry_ = dirEntry; |
2043 this.dispatchEvent(e); | 2009 this.dispatchEvent(e); |
2044 } | 2010 } |
2045 | 2011 |
2046 /** | 2012 /** |
2047 * Change the current directory to the directory represented by a string | 2013 * Change the current directory to the directory represented by a string |
2048 * path. | 2014 * path. |
2049 * | 2015 * |
2050 * Dispatches the 'directory-changed' event when the directory is successfully | 2016 * Dispatches the 'directory-changed' event when the directory is successfully |
2051 * changed. | 2017 * changed. |
2052 * | 2018 * |
2053 * @param {string} path The absolute path to the new directory. | 2019 * @param {string} path The absolute path to the new directory. |
2054 * @param {bool} opt_saveHistory Save this in the history stack (defaults | 2020 * @param {bool} opt_saveHistory Save this in the history stack (defaults |
2055 * to true). | 2021 * to true). |
2056 * @param {string} opt_selectedEntry The name of the file to select after | 2022 * @param {string} opt_selectedEntry The name of the file to select after |
2057 * changing directories. | 2023 * changing directories. |
2058 */ | 2024 */ |
2059 FileManager.prototype.changeDirectory = function(path, | 2025 FileManager.prototype.changeDirectory = function(path, |
2060 opt_saveHistory, | 2026 opt_saveHistory, |
2061 opt_selectedEntry) { | 2027 opt_selectedEntry) { |
2062 if (path == '/') | 2028 if (path == '/') |
2063 return this.changeDirectoryEntry(this.filesystem_.root, | 2029 return this.changeDirectoryEntry(this.filesystem_.root); |
2064 opt_saveHistory, | |
2065 opt_selectedEntry); | |
2066 | 2030 |
2067 var self = this; | 2031 var self = this; |
2068 | 2032 |
2069 this.filesystem_.root.getDirectory( | 2033 this.filesystem_.root.getDirectory( |
2070 path, {create: false}, | 2034 path, {create: false}, |
2071 function(dirEntry) { | 2035 function(dirEntry) { |
2072 self.changeDirectoryEntry( | 2036 self.changeDirectoryEntry( |
2073 dirEntry, opt_saveHistory, opt_selectedEntry); | 2037 dirEntry, opt_saveHistory, opt_selectedEntry); |
2074 }, | 2038 }, |
2075 function(err) { | 2039 function(err) { |
2076 console.error('Error changing directory to: ' + path + ', ' + err); | 2040 console.error('Error changing directory to: ' + path + ', ' + err); |
2077 if (self.currentDirEntry_) { | 2041 if (!self.currentDirEntry_) { |
2078 var location = '#' + encodeURI(self.currentDirEntry_.fullPath); | |
2079 history.replaceState(undefined, | |
2080 self.currentDirEntry_.fullPath, | |
2081 location); | |
2082 } else { | |
2083 // If we've never successfully changed to a directory, force them | 2042 // If we've never successfully changed to a directory, force them |
2084 // to the root. | 2043 // to the root. |
2085 self.changeDirectory('/', false); | 2044 self.changeDirectory('/', false); |
2086 } | 2045 } |
2087 }); | 2046 }); |
2088 }; | 2047 }; |
2089 | 2048 |
2090 FileManager.prototype.deleteEntries = function(entries, force) { | 2049 FileManager.prototype.deleteEntries = function(entries, force) { |
2091 if (!force) { | 2050 if (!force) { |
2092 var self = this; | 2051 var self = this; |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2364 this.onOk_(); | 2323 this.onOk_(); |
2365 | 2324 |
2366 }; | 2325 }; |
2367 | 2326 |
2368 /** | 2327 /** |
2369 * Update the UI when the current directory changes. | 2328 * Update the UI when the current directory changes. |
2370 * | 2329 * |
2371 * @param {cr.Event} event The directory-changed event. | 2330 * @param {cr.Event} event The directory-changed event. |
2372 */ | 2331 */ |
2373 FileManager.prototype.onDirectoryChanged_ = function(event) { | 2332 FileManager.prototype.onDirectoryChanged_ = function(event) { |
| 2333 if (event.saveHistory) { |
| 2334 history.pushState(this.currentDirEntry_.fullPath, |
| 2335 this.currentDirEntry_.fullPath, |
| 2336 location.href); |
| 2337 } |
| 2338 |
2374 this.updateCommands_(); | 2339 this.updateCommands_(); |
2375 this.updateOkButton_(); | 2340 this.updateOkButton_(); |
2376 | 2341 |
2377 // New folder should never be enabled in the root or media/ directories. | 2342 // New folder should never be enabled in the root or media/ directories. |
2378 this.newFolderButton_.disabled = isSystemDirEntry(this.currentDirEntry_); | 2343 this.newFolderButton_.disabled = isSystemDirEntry(this.currentDirEntry_); |
2379 | 2344 |
2380 this.document_.title = this.currentDirEntry_.fullPath; | 2345 this.document_.title = this.currentDirEntry_.fullPath; |
2381 | 2346 |
2382 var self = this; | 2347 var self = this; |
2383 this.rescanDirectory_(function() { | 2348 this.rescanDirectory_(function() { |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2832 case 69: // Ctrl-E => Rename. | 2797 case 69: // Ctrl-E => Rename. |
2833 this.updateCommands_(); | 2798 this.updateCommands_(); |
2834 if (!this.commands_['rename'].disabled) { | 2799 if (!this.commands_['rename'].disabled) { |
2835 event.preventDefault(); | 2800 event.preventDefault(); |
2836 this.commands_['rename'].execute(); | 2801 this.commands_['rename'].execute(); |
2837 } | 2802 } |
2838 break; | 2803 break; |
2839 | 2804 |
2840 case 46: // Delete. | 2805 case 46: // Delete. |
2841 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE && | 2806 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE && |
2842 this.selection && this.selection.totalCount > 0 && | 2807 this.selection.totalCount > 0 && |
2843 !isSystemDirEntry(this.currentDirEntry_)) { | 2808 !isSystemDirEntry(this.currentDirEntry_)) { |
2844 event.preventDefault(); | 2809 event.preventDefault(); |
2845 this.deleteEntries(this.selection.entries); | 2810 this.deleteEntries(this.selection.entries); |
2846 } | 2811 } |
2847 break; | 2812 break; |
2848 } | 2813 } |
2849 }; | 2814 }; |
2850 | 2815 |
2851 /** | 2816 /** |
2852 * KeyPress event handler for the div.list-container element. | 2817 * KeyPress event handler for the div.list-container element. |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3030 | 2995 |
3031 if (msg) { | 2996 if (msg) { |
3032 console.log('no no no'); | 2997 console.log('no no no'); |
3033 this.alert.show(msg, onAccept); | 2998 this.alert.show(msg, onAccept); |
3034 return false; | 2999 return false; |
3035 } | 3000 } |
3036 | 3001 |
3037 return true; | 3002 return true; |
3038 }; | 3003 }; |
3039 })(); | 3004 })(); |
OLD | NEW |