Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(382)

Side by Side Diff: chrome/browser/resources/file_manager/js/file_manager.js

Issue 10392155: Fixing race condition in prepearing thumbnails for the bottom panel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/resources/file_manager/css/file_manager.css ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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;
Vladislav Kaznacheev 2012/05/18 11:43:40 Do we need both |hidden| attribute and |has-zoom|
SeRya 2012/05/18 12:06:07 If we only play with the class it triggers animati
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
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 presents.
Vladislav Kaznacheev 2012/05/18 11:43:40 presents -> is present
SeRya 2012/05/18 12:06:07 Done.
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
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 })();
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/css/file_manager.css ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698