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