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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 } | 56 } |
57 | 57 |
| 58 /** |
| 59 * Maximum delay in milliseconds for updating thumbnails in the bottom panel |
| 60 * to mitigate flickering. If images load faster then the delay they replace |
| 61 * old images smoothly. On the other hand we don't want to keep old images |
| 62 * too long. |
| 63 */ |
| 64 FileManager.THUMBNAIL_SHOW_DELAY = 100; |
| 65 |
58 FileManager.prototype = { | 66 FileManager.prototype = { |
59 __proto__: cr.EventTarget.prototype | 67 __proto__: cr.EventTarget.prototype |
60 }; | 68 }; |
61 | 69 |
62 // Anonymous "namespace". | 70 // Anonymous "namespace". |
63 (function() { | 71 (function() { |
64 | 72 |
65 // Private variables and helper functions. | 73 // Private variables and helper functions. |
66 | 74 |
67 /** | 75 /** |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 if (x[0] == '/') | 225 if (x[0] == '/') |
218 return x.slice(1); | 226 return x.slice(1); |
219 else | 227 else |
220 return x; | 228 return x; |
221 } | 229 } |
222 | 230 |
223 function removeChildren(element) { | 231 function removeChildren(element) { |
224 element.textContent = ''; | 232 element.textContent = ''; |
225 } | 233 } |
226 | 234 |
| 235 function setClassIf(element, className, condition) { |
| 236 if (condition) |
| 237 element.classList.add(className); |
| 238 else |
| 239 element.classList.remove(className); |
| 240 } |
| 241 |
227 // Public statics. | 242 // Public statics. |
228 | 243 |
229 /** | 244 /** |
230 * List of dialog types. | 245 * List of dialog types. |
231 * | 246 * |
232 * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except | 247 * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except |
233 * FULL_PAGE which is specific to this code. | 248 * FULL_PAGE which is specific to this code. |
234 * | 249 * |
235 * @enum {string} | 250 * @enum {string} |
236 */ | 251 */ |
(...skipping 1851 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2088 }; | 2103 }; |
2089 | 2104 |
2090 if (!selection.indexes.length) { | 2105 if (!selection.indexes.length) { |
2091 this.updateCommonActionButtons_(); | 2106 this.updateCommonActionButtons_(); |
2092 this.updatePreviewPanelVisibility_(); | 2107 this.updatePreviewPanelVisibility_(); |
2093 cr.dispatchSimpleEvent(this, 'selection-summarized'); | 2108 cr.dispatchSimpleEvent(this, 'selection-summarized'); |
2094 return; | 2109 return; |
2095 } | 2110 } |
2096 | 2111 |
2097 this.previewSummary_.textContent = str('COMPUTING_SELECTION'); | 2112 this.previewSummary_.textContent = str('COMPUTING_SELECTION'); |
2098 var thumbnails = this.document_.createDocumentFragment(); | 2113 var thumbnails = []; |
2099 | 2114 |
2100 var pendingFiles = []; | 2115 var pendingFiles = []; |
2101 var thumbnailCount = 0; | 2116 var thumbnailCount = 0; |
2102 var thumbnailLoaded = -1; | 2117 var thumbnailLoaded = -1; |
2103 var forcedShowTimeout = null; | 2118 var forcedShowTimeout = null; |
| 2119 var thumbnailsHaveZoom = false; |
2104 var self = this; | 2120 var self = this; |
2105 | 2121 |
2106 function showThumbnails() { | 2122 function showThumbnails() { |
| 2123 // have-zoom class may be updated twice: then timeout exceeds and then |
| 2124 // then all images loaded. |
| 2125 if (self.selection == selection) |
| 2126 setClassIf(self.previewThumbnails_, 'has-zoom', thumbnailsHaveZoom); |
| 2127 |
2107 if (forcedShowTimeout === null) | 2128 if (forcedShowTimeout === null) |
2108 return; | 2129 return; |
2109 clearTimeout(forcedShowTimeout); | 2130 clearTimeout(forcedShowTimeout); |
2110 forcedShowTimeout = null; | 2131 forcedShowTimeout = null; |
2111 | 2132 |
2112 // Selection could change while images are loading. | 2133 // Selection could change while images are loading. |
2113 if (self.selection == selection) { | 2134 if (self.selection == selection) { |
2114 removeChildren(self.previewThumbnails_); | 2135 removeChildren(self.previewThumbnails_); |
2115 self.previewThumbnails_.appendChild(thumbnails); | 2136 for (var i = 0; i < thumbnails.length; i++) |
| 2137 self.previewThumbnails_.appendChild(thumbnails[i]); |
2116 } | 2138 } |
2117 } | 2139 } |
2118 | 2140 |
2119 function onThumbnailLoaded() { | 2141 function onThumbnailLoaded() { |
2120 thumbnailLoaded++; | 2142 thumbnailLoaded++; |
2121 if (thumbnailLoaded == thumbnailCount) | 2143 if (thumbnailLoaded == thumbnailCount) |
2122 showThumbnails(); | 2144 showThumbnails(); |
2123 } | 2145 } |
2124 | 2146 |
2125 for (var i = 0; i < selection.indexes.length; i++) { | 2147 for (var i = 0; i < selection.indexes.length; i++) { |
2126 var entry = this.directoryModel_.getFileList().item(selection.indexes[i]); | 2148 var entry = this.directoryModel_.getFileList().item(selection.indexes[i]); |
2127 if (!entry) | 2149 if (!entry) |
2128 continue; | 2150 continue; |
2129 | 2151 |
2130 selection.entries.push(entry); | 2152 selection.entries.push(entry); |
2131 selection.urls.push(entry.toURL()); | 2153 selection.urls.push(entry.toURL()); |
2132 | 2154 |
2133 if (thumbnailCount < MAX_PREVIEW_THUMBAIL_COUNT) { | 2155 if (thumbnailCount < MAX_PREVIEW_THUMBAIL_COUNT) { |
2134 var box = this.document_.createElement('div'); | 2156 var box = this.document_.createElement('div'); |
2135 box.className = 'thumbnail'; | 2157 box.className = 'thumbnail'; |
2136 function imageLoadCalback(index, box, img, transform) { | 2158 if (thumbnailCount == 0) { |
2137 if (index == 0) | 2159 var zoomed = this.document_.createElement('div'); |
2138 thumbnails.insertBefore(self.renderThumbnailZoom_(img, transform), | 2160 zoomed.hidden = true; |
2139 thumbnails.firstChild); | 2161 thumbnails.push(zoomed); |
2140 onThumbnailLoaded(); | 2162 function onFirstThumbnailLoaded(img, transform) { |
| 2163 if (self.decorateThumbnailZoom_(zoomed, img, transform)) { |
| 2164 zoomed.hidden = false; |
| 2165 thumbnailsHaveZoom = true; |
| 2166 } |
| 2167 onThumbnailLoaded(); |
| 2168 } |
| 2169 var thumbnail = this.renderThumbnailBox_(entry, true, |
| 2170 onFirstThumbnailLoaded); |
| 2171 } else { |
| 2172 var thumbnail = this.renderThumbnailBox_(entry, true, |
| 2173 onThumbnailLoaded); |
2141 } | 2174 } |
2142 var thumbnail = this.renderThumbnailBox_(entry, true, | |
2143 imageLoadCalback.bind(null, thumbnailCount, box)); | |
2144 thumbnailCount++; | 2175 thumbnailCount++; |
2145 box.appendChild(thumbnail); | 2176 box.appendChild(thumbnail); |
2146 box.style.zIndex = MAX_PREVIEW_THUMBAIL_COUNT + 1 - i; | 2177 box.style.zIndex = MAX_PREVIEW_THUMBAIL_COUNT + 1 - i; |
2147 box.addEventListener('click', | 2178 box.addEventListener('click', |
2148 this.dispatchDefaultTask_.bind(this, selection)); | 2179 this.dispatchDefaultTask_.bind(this, selection)); |
2149 | 2180 |
2150 thumbnails.appendChild(box); | 2181 thumbnails.push(box); |
2151 } | 2182 } |
2152 | 2183 |
2153 if (selection.iconType == null) { | 2184 if (selection.iconType == null) { |
2154 selection.iconType = FileType.getIcon(entry); | 2185 selection.iconType = FileType.getIcon(entry); |
2155 } else if (selection.iconType != 'unknown') { | 2186 } else if (selection.iconType != 'unknown') { |
2156 var iconType = FileType.getIcon(entry); | 2187 var iconType = FileType.getIcon(entry); |
2157 if (selection.iconType != iconType) | 2188 if (selection.iconType != iconType) |
2158 selection.iconType = 'unknown'; | 2189 selection.iconType = 'unknown'; |
2159 } | 2190 } |
2160 | 2191 |
2161 if (entry.isFile) { | 2192 if (entry.isFile) { |
2162 selection.fileCount += 1; | 2193 selection.fileCount += 1; |
2163 selection.showBytes |= !FileType.isHosted(entry); | 2194 selection.showBytes |= !FileType.isHosted(entry); |
2164 } else { | 2195 } else { |
2165 selection.directoryCount += 1; | 2196 selection.directoryCount += 1; |
2166 } | 2197 } |
2167 selection.totalCount++; | 2198 selection.totalCount++; |
2168 } | 2199 } |
2169 | 2200 |
2170 // Now this.selection is complete. Update buttons. | 2201 // Now this.selection is complete. Update buttons. |
2171 this.updateCommonActionButtons_(); | 2202 this.updateCommonActionButtons_(); |
2172 this.updatePreviewPanelVisibility_(); | 2203 this.updatePreviewPanelVisibility_(); |
2173 forcedShowTimeout = setTimeout(showThumbnails, 100); | 2204 forcedShowTimeout = setTimeout(showThumbnails, |
| 2205 FileManager.THUMBNAIL_SHOW_DELAY); |
2174 onThumbnailLoaded(); | 2206 onThumbnailLoaded(); |
2175 | 2207 |
2176 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE) { | 2208 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE) { |
2177 // Some internal tasks cannot be defined in terms of file patterns, | 2209 // Some internal tasks cannot be defined in terms of file patterns, |
2178 // so we pass selection to check for them manually. | 2210 // so we pass selection to check for them manually. |
2179 if (selection.directoryCount == 0 && selection.fileCount > 0) { | 2211 if (selection.directoryCount == 0 && selection.fileCount > 0) { |
2180 // Only files, not directories, are supported for external tasks. | 2212 // Only files, not directories, are supported for external tasks. |
2181 chrome.fileBrowserPrivate.getFileTasks( | 2213 chrome.fileBrowserPrivate.getFileTasks( |
2182 selection.urls, | 2214 selection.urls, |
2183 this.onTasksFound_.bind(this, selection)); | 2215 this.onTasksFound_.bind(this, selection)); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2218 FileManager.prototype.isSelectionAvailable = function() { | 2250 FileManager.prototype.isSelectionAvailable = function() { |
2219 return !this.isOnGData() || | 2251 return !this.isOnGData() || |
2220 !this.isOffline() || | 2252 !this.isOffline() || |
2221 this.selection.allGDataFilesPresent; | 2253 this.selection.allGDataFilesPresent; |
2222 }; | 2254 }; |
2223 | 2255 |
2224 /** | 2256 /** |
2225 * Creates enlarged image for a bottom pannel thumbnail. | 2257 * Creates enlarged image for a bottom pannel thumbnail. |
2226 * Image's assumed to be just loaded and not inserted into the DOM. | 2258 * Image's assumed to be just loaded and not inserted into the DOM. |
2227 * | 2259 * |
| 2260 * @param {HTMLElement} largeImageBox DIV element to decorate. |
2228 * @param {HTMLElement} img Loaded image. | 2261 * @param {HTMLElement} img Loaded image. |
2229 * @param {Object} transform Image transformation description. | 2262 * @param {Object} transform Image transformation description. |
2230 * @return {Element} Created element. | 2263 * @return {boolean} True if zoomed image is present. |
2231 */ | 2264 */ |
2232 FileManager.prototype.renderThumbnailZoom_ = function(img, transform) { | 2265 FileManager.prototype.decorateThumbnailZoom_ = function(largeImageBox, |
| 2266 img, transform) { |
2233 var width = img.width; | 2267 var width = img.width; |
2234 var height = img.height; | 2268 var height = img.height; |
2235 var THUMBNAIL_SIZE = 45; | 2269 var THUMBNAIL_SIZE = 45; |
2236 | |
2237 if (width < THUMBNAIL_SIZE * 2 && height < THUMBNAIL_SIZE * 2) | 2270 if (width < THUMBNAIL_SIZE * 2 && height < THUMBNAIL_SIZE * 2) |
2238 return; | 2271 return false; |
2239 | 2272 |
2240 var scale = Math.min(1, | 2273 var scale = Math.min(1, |
2241 IMAGE_HOVER_PREVIEW_SIZE / Math.max(width, height)); | 2274 IMAGE_HOVER_PREVIEW_SIZE / Math.max(width, height)); |
2242 | 2275 |
2243 var imageWidth = Math.round(width * scale); | 2276 var imageWidth = Math.round(width * scale); |
2244 var imageHeight = Math.round(height * scale); | 2277 var imageHeight = Math.round(height * scale); |
2245 | 2278 |
2246 var largeImage = this.document_.createElement('img'); | 2279 var largeImage = this.document_.createElement('img'); |
2247 if (scale < 0.3) { | 2280 if (scale < 0.3) { |
2248 // Scaling large images kills animation. Downscale it in advance. | 2281 // Scaling large images kills animation. Downscale it in advance. |
2249 | 2282 |
2250 // Canvas scales images with liner interpolation. Make a larger | 2283 // Canvas scales images with liner interpolation. Make a larger |
2251 // image (but small enough to not kill animation) and let IMG | 2284 // image (but small enough to not kill animation) and let IMG |
2252 // scale it smoothly. | 2285 // scale it smoothly. |
2253 var INTERMEDIATE_SCALE = 3; | 2286 var INTERMEDIATE_SCALE = 3; |
2254 var canvas = this.document_.createElement('canvas'); | 2287 var canvas = this.document_.createElement('canvas'); |
2255 canvas.width = imageWidth * INTERMEDIATE_SCALE; | 2288 canvas.width = imageWidth * INTERMEDIATE_SCALE; |
2256 canvas.height = imageHeight * INTERMEDIATE_SCALE; | 2289 canvas.height = imageHeight * INTERMEDIATE_SCALE; |
2257 var ctx = canvas.getContext('2d'); | 2290 var ctx = canvas.getContext('2d'); |
2258 ctx.drawImage(img, 0, 0, canvas.width, canvas.height); | 2291 ctx.drawImage(img, 0, 0, canvas.width, canvas.height); |
2259 // Using bigger than default compression reduces image size by | 2292 // Using bigger than default compression reduces image size by |
2260 // several times. Quality degradation compensated by greater resolution. | 2293 // several times. Quality degradation compensated by greater resolution. |
2261 largeImage.src = canvas.toDataURL('image/jpeg', 0.6); | 2294 largeImage.src = canvas.toDataURL('image/jpeg', 0.6); |
2262 } else { | 2295 } else { |
2263 largeImage.src = img.src; | 2296 largeImage.src = img.src; |
2264 } | 2297 } |
2265 var largeImageBox = this.document_.createElement('div'); | |
2266 largeImageBox.className = 'popup'; | 2298 largeImageBox.className = 'popup'; |
2267 | 2299 |
2268 var boxWidth = Math.max(THUMBNAIL_SIZE, imageWidth); | 2300 var boxWidth = Math.max(THUMBNAIL_SIZE, imageWidth); |
2269 var boxHeight = Math.max(THUMBNAIL_SIZE, imageHeight); | 2301 var boxHeight = Math.max(THUMBNAIL_SIZE, imageHeight); |
2270 | 2302 |
2271 if (transform && transform.rotate90 % 2 == 1) { | 2303 if (transform && transform.rotate90 % 2 == 1) { |
2272 var t = boxWidth; | 2304 var t = boxWidth; |
2273 boxWidth = boxHeight; | 2305 boxWidth = boxHeight; |
2274 boxHeight = t; | 2306 boxHeight = t; |
2275 } | 2307 } |
2276 | 2308 |
2277 var style = largeImageBox.style; | 2309 var style = largeImageBox.style; |
2278 style.width = boxWidth + 'px'; | 2310 style.width = boxWidth + 'px'; |
2279 style.height = boxHeight + 'px'; | 2311 style.height = boxHeight + 'px'; |
2280 style.top = (-boxHeight + THUMBNAIL_SIZE) + 'px'; | 2312 style.top = (-boxHeight + THUMBNAIL_SIZE) + 'px'; |
2281 | 2313 |
2282 var style = largeImage.style; | 2314 var style = largeImage.style; |
2283 style.width = imageWidth + 'px'; | 2315 style.width = imageWidth + 'px'; |
2284 style.height = imageHeight + 'px'; | 2316 style.height = imageHeight + 'px'; |
2285 style.left = (boxWidth - imageWidth) / 2 + 'px'; | 2317 style.left = (boxWidth - imageWidth) / 2 + 'px'; |
2286 style.top = (boxHeight - imageHeight) / 2 + 'px'; | 2318 style.top = (boxHeight - imageHeight) / 2 + 'px'; |
2287 style.position = 'relative'; | 2319 style.position = 'relative'; |
2288 | 2320 |
2289 util.applyTransform(largeImage, transform); | 2321 util.applyTransform(largeImage, transform); |
2290 | 2322 |
2291 largeImageBox.appendChild(largeImage); | 2323 largeImageBox.appendChild(largeImage); |
2292 largeImageBox.style.zIndex = 1000; | 2324 largeImageBox.style.zIndex = 1000; |
2293 return largeImageBox; | 2325 return true; |
2294 }; | 2326 }; |
2295 | 2327 |
2296 FileManager.prototype.updatePreviewPanelVisibility_ = function() { | 2328 FileManager.prototype.updatePreviewPanelVisibility_ = function() { |
2297 var panel = this.previewPanel_; | 2329 var panel = this.previewPanel_; |
2298 var state = panel.getAttribute('visibility'); | 2330 var state = panel.getAttribute('visibility'); |
2299 var mustBeVisible = (this.selection.totalCount > 0); | 2331 var mustBeVisible = (this.selection.totalCount > 0); |
2300 var self = this; | 2332 var self = this; |
2301 | 2333 |
2302 switch (state) { | 2334 switch (state) { |
2303 case 'visible': | 2335 case 'visible': |
(...skipping 2322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4626 | 4658 |
4627 function closeBanner() { | 4659 function closeBanner() { |
4628 self.cleanupGDataWelcome_(); | 4660 self.cleanupGDataWelcome_(); |
4629 // Stop showing the welcome banner. | 4661 // Stop showing the welcome banner. |
4630 localStorage[WELCOME_HEADER_COUNTER_KEY] = WELCOME_HEADER_COUNTER_LIMIT; | 4662 localStorage[WELCOME_HEADER_COUNTER_KEY] = WELCOME_HEADER_COUNTER_LIMIT; |
4631 } | 4663 } |
4632 | 4664 |
4633 return maybeShowBanner; | 4665 return maybeShowBanner; |
4634 }; | 4666 }; |
4635 })(); | 4667 })(); |
OLD | NEW |