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

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

Issue 8890017: Fixed renaming in the file manager. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Removing unnecessary changes. Created 9 years 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 | « no previous file | 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) 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 // If directory files changes too often, don't rescan directory more than once 10 // If directory files changes too often, don't rescan directory more than once
(...skipping 1119 matching lines...) Expand 10 before | Expand all | Expand 10 after
1130 }; 1130 };
1131 1131
1132 /** 1132 /**
1133 * Initialize the file thumbnail grid. 1133 * Initialize the file thumbnail grid.
1134 */ 1134 */
1135 FileManager.prototype.initGrid_ = function() { 1135 FileManager.prototype.initGrid_ = function() {
1136 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid'); 1136 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid');
1137 cr.ui.Grid.decorate(this.grid_); 1137 cr.ui.Grid.decorate(this.grid_);
1138 1138
1139 var self = this; 1139 var self = this;
1140 this.grid_.itemConstructor = function(entry) { 1140 this.grid_.itemConstructor = GridItem.bind(null, this);
1141 return self.renderThumbnail_(entry);
1142 };
1143 1141
1144 this.grid_.selectionModel = new this.selectionModelClass_(); 1142 this.grid_.selectionModel = new this.selectionModelClass_();
1145 1143
1146 this.grid_.addEventListener( 1144 this.grid_.addEventListener(
1147 'dblclick', this.onDetailDoubleClick_.bind(this)); 1145 'dblclick', this.onDetailDoubleClick_.bind(this));
1148 this.grid_.selectionModel.addEventListener( 1146 this.grid_.selectionModel.addEventListener(
1149 'change', this.onSelectionChanged_.bind(this)); 1147 'change', this.onSelectionChanged_.bind(this));
1150 cr.ui.contextMenuHandler.addContextMenuProperty(this.grid_); 1148 cr.ui.contextMenuHandler.addContextMenuProperty(this.grid_);
1151 this.grid_.contextMenu = this.fileContextMenu_; 1149 this.grid_.contextMenu = this.fileContextMenu_;
1152 this.grid_.addEventListener('mousedown', 1150 this.grid_.addEventListener('mousedown',
(...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after
1656 if (opt_imageLoadCallback) 1654 if (opt_imageLoadCallback)
1657 opt_imageLoadCallback(img, transform); 1655 opt_imageLoadCallback(img, transform);
1658 box.appendChild(img); 1656 box.appendChild(img);
1659 }; 1657 };
1660 img.src = url; 1658 img.src = url;
1661 self.applyImageTransformation_(box, transform); 1659 self.applyImageTransformation_(box, transform);
1662 }); 1660 });
1663 return box; 1661 return box;
1664 }; 1662 };
1665 1663
1666 FileManager.prototype.renderThumbnail_ = function(entry) { 1664 function GridItem(fileManager, entry) {
1667 var li = this.document_.createElement('li'); 1665 var li = fileManager.document_.createElement('li');
1666 GridItem.decorate(li, fileManager, entry);
1667 return li;
1668 }
1669
1670 GridItem.prototype = {
1671 __proto__: cr.ui.ListItem.prototype,
1672
1673 get label() {
1674 return this.querySelector('filename-label').textContent;
1675 },
1676 set label(value) {
1677 // Grid sets it to entry. Ignore.
1678 }
1679 };
1680
1681 GridItem.decorate = function(li, fileManager, entry) {
1682 li.__proto__ = GridItem.prototype;
1683 fileManager.decorateThumbnail_(li, entry);
1684 };
1685
1686 FileManager.prototype.decorateThumbnail_ = function(li, entry) {
1668 li.className = 'thumbnail-item'; 1687 li.className = 'thumbnail-item';
1669 1688
1670 if (this.showCheckboxes_) 1689 if (this.showCheckboxes_)
1671 li.appendChild(this.renderCheckbox_(entry)); 1690 li.appendChild(this.renderCheckbox_(entry));
1672 1691
1673 li.appendChild(this.renderThumbnailBox_(entry, false)); 1692 li.appendChild(this.renderThumbnailBox_(entry, false));
1674 1693
1675 var div = this.document_.createElement('div'); 1694 var div = this.document_.createElement('div');
1676 div.className = 'filename-label'; 1695 div.className = 'filename-label';
1677 var labelText = entry.name; 1696 var labelText = entry.name;
1678 if (this.currentDirEntry_.name == '') 1697 if (this.currentDirEntry_.name == '')
1679 labelText = this.getLabelForRootPath_(labelText); 1698 labelText = this.getLabelForRootPath_(labelText);
1680 1699
1681 div.textContent = labelText; 1700 div.textContent = labelText;
1682 div.entry = entry; 1701 div.entry = entry;
1683 1702
1684 li.appendChild(div); 1703 li.appendChild(div);
1704 };
1685 1705
1686 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); 1706 GridItem.prototype.__proto__ = cr.ui.ListItem.prototype;
dgozman 2011/12/09 11:14:43 This is already set above.
SeRya 2011/12/09 14:31:13 Removed.
1687 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR);
1688 return li;
1689 };
1690 1707
1691 /** 1708 /**
1692 * Render the type column of the detail table. 1709 * Render the type column of the detail table.
1693 * 1710 *
1694 * Invoked by cr.ui.Table when a file needs to be rendered. 1711 * Invoked by cr.ui.Table when a file needs to be rendered.
1695 * 1712 *
1696 * @param {Entry} entry The Entry object to render. 1713 * @param {Entry} entry The Entry object to render.
1697 * @param {string} columnId The id of the column to be rendered. 1714 * @param {string} columnId The id of the column to be rendered.
1698 * @param {cr.ui.Table} table The table doing the rendering. 1715 * @param {cr.ui.Table} table The table doing the rendering.
1699 */ 1716 */
(...skipping 28 matching lines...) Expand all
1728 * @param {string} columnId The id of the column to be rendered. 1745 * @param {string} columnId The id of the column to be rendered.
1729 * @param {cr.ui.Table} table The table doing the rendering. 1746 * @param {cr.ui.Table} table The table doing the rendering.
1730 */ 1747 */
1731 FileManager.prototype.renderName_ = function(entry, columnId, table) { 1748 FileManager.prototype.renderName_ = function(entry, columnId, table) {
1732 var label = this.document_.createElement('div'); 1749 var label = this.document_.createElement('div');
1733 if (this.showCheckboxes_) 1750 if (this.showCheckboxes_)
1734 label.appendChild(this.renderCheckbox_(entry)); 1751 label.appendChild(this.renderCheckbox_(entry));
1735 label.appendChild(this.renderIconType_(entry, columnId, table)); 1752 label.appendChild(this.renderIconType_(entry, columnId, table));
1736 label.entry = entry; 1753 label.entry = entry;
1737 label.className = 'detail-name'; 1754 label.className = 'detail-name';
1755 // Filename need to be in a '.filename-label' container for correct
1756 // work of inplace renaming.
1757 var fileName = this.document_.createElement('div');
1758 fileName.className = 'filename-label';
1738 if (this.currentDirEntry_.name == '') { 1759 if (this.currentDirEntry_.name == '') {
1739 label.appendChild(this.document_.createTextNode( 1760 fileName.appendChild(this.document_.createTextNode(
dgozman 2011/12/09 11:14:43 You can use instead: fileName.textContent = this.g
SeRya 2011/12/09 14:31:13 Fixed and extracted to a method to avoid code dupl
1740 this.getLabelForRootPath_(entry.name))); 1761 this.getLabelForRootPath_(entry.name)));
1741 } else { 1762 } else {
1742 label.appendChild(this.document_.createTextNode(entry.name)); 1763 fileName.appendChild(this.document_.createTextNode(entry.name));
1743 } 1764 }
1765 label.appendChild(fileName);
1744 1766
1745 return label; 1767 return label;
1746 }; 1768 };
1747 1769
1748 /** 1770 /**
1749 * Render the Size column of the detail table. 1771 * Render the Size column of the detail table.
1750 * 1772 *
1751 * @param {Entry} entry The Entry object to render. 1773 * @param {Entry} entry The Entry object to render.
1752 * @param {string} columnId The id of the column to be rendered. 1774 * @param {string} columnId The id of the column to be rendered.
1753 * @param {cr.ui.Table} table The table doing the rendering. 1775 * @param {cr.ui.Table} table The table doing the rendering.
(...skipping 1489 matching lines...) Expand 10 before | Expand all | Expand 10 after
3243 FileManager.prototype.prefetchCacheForSorting_ = function(entries, callback) { 3265 FileManager.prototype.prefetchCacheForSorting_ = function(entries, callback) {
3244 var field = this.dataModel_.sortStatus.field; 3266 var field = this.dataModel_.sortStatus.field;
3245 if (field) { 3267 if (field) {
3246 this.prepareSortEntries_(entries, field, callback); 3268 this.prepareSortEntries_(entries, field, callback);
3247 } else { 3269 } else {
3248 callback(); 3270 callback();
3249 return; 3271 return;
3250 } 3272 }
3251 }; 3273 };
3252 3274
3253 FileManager.prototype.findListItem_ = function(event) { 3275 FileManager.prototype.findListItemForEvent_ = function(event, list) {
3254 var node = event.srcElement; 3276 var node = event.srcElement;
3277 // Assume list items are direct children of the list.
3278 if (node == list)
3279 return null;
3255 while (node) { 3280 while (node) {
3256 if (node.tagName == 'LI') 3281 var parent = node.parentNode;
3257 break; 3282 if (parent == list)
3258 node = node.parentNode; 3283 return node;
3284 node = parent;
3259 } 3285 }
3260 3286 return null;
3261 return node;
3262 }; 3287 };
3263 3288
3264 FileManager.prototype.onGridMouseDown_ = function(event) { 3289 FileManager.prototype.onGridMouseDown_ = function(event) {
3265 this.updateCommands_(); 3290 this.updateCommands_();
3266 3291
3267 if (this.allowRenameClick_(event, event.srcElement.parentNode)) { 3292 var list = this.grid_;
3293 var item = this.findListItemForEvent_(event, list);
3294 if (!item)
3295 return;
3296 if (this.allowRenameClick_(event, list, item)) {
3268 event.preventDefault(); 3297 event.preventDefault();
3269 this.initiateRename_(event.srcElement); 3298 this.initiateRename_(list, item);
3270 } 3299 }
3271
3272 if (event.button != 1)
3273 return;
3274
3275 var li = this.findListItem_(event);
3276 if (!li)
3277 return;
3278 }; 3300 };
3279 3301
3280 FileManager.prototype.onTableMouseDown_ = function(event) { 3302 FileManager.prototype.onTableMouseDown_ = function(event) {
3281 this.updateCommands_(); 3303 this.updateCommands_();
3282 3304
3283 if (this.allowRenameClick_(event, 3305 var list = this.table_.list;
3284 event.srcElement.parentNode.parentNode)) { 3306 var item = this.findListItemForEvent_(event, list);
3307 if (!item)
3308 return;
3309 if (this.allowRenameClick_(event, list, item)) {
3285 event.preventDefault(); 3310 event.preventDefault();
3286 this.initiateRename_(event.srcElement); 3311 this.initiateRename_(list, item);
3287 }
3288
3289 if (event.button != 1)
3290 return;
3291
3292 var li = this.findListItem_(event);
3293 if (!li) {
3294 console.log('li not found', event);
3295 return;
3296 } 3312 }
3297 }; 3313 };
3298 3314
3299 /** 3315 /**
3300 * Unload handler for the page. May be called manually for the file picker 3316 * Unload handler for the page. May be called manually for the file picker
3301 * dialog, because it closes by calling extension API functions that do not 3317 * dialog, because it closes by calling extension API functions that do not
3302 * return. 3318 * return.
3303 */ 3319 */
3304 FileManager.prototype.onUnload_ = function() { 3320 FileManager.prototype.onUnload_ = function() {
3305 if (this.subscribedOnDirectoryChanges_) { 3321 if (this.subscribedOnDirectoryChanges_) {
(...skipping 12 matching lines...) Expand all
3318 if (event.fileUrl == this.currentDirEntry_.toURL()) 3334 if (event.fileUrl == this.currentDirEntry_.toURL())
3319 this.rescanDirectoryLater_(); 3335 this.rescanDirectoryLater_();
3320 }; 3336 };
3321 3337
3322 /** 3338 /**
3323 * Determine whether or not a click should initiate a rename. 3339 * Determine whether or not a click should initiate a rename.
3324 * 3340 *
3325 * Renames can happen on mouse click if the user clicks on a label twice, 3341 * Renames can happen on mouse click if the user clicks on a label twice,
3326 * at least a half second apart. 3342 * at least a half second apart.
3327 */ 3343 */
3328 FileManager.prototype.allowRenameClick_ = function(event, row) { 3344 FileManager.prototype.allowRenameClick_ = function(event, list, item) {
3329 if (this.dialogType_ != FileManager.DialogType.FULL_PAGE || 3345 if (this.dialogType_ != FileManager.DialogType.FULL_PAGE ||
3330 this.currentDirEntry_ == null || this.currentDirEntry_.name == '' || 3346 this.currentDirEntry_ == null || this.currentDirEntry_.name == '' ||
3331 isSystemDirEntry(this.currentDirEntry_)) { 3347 isSystemDirEntry(this.currentDirEntry_)) {
3332 // Renaming only enabled for full-page mode, outside of the root 3348 // Renaming only enabled for full-page mode, outside of the root
3333 // directory. 3349 // directory.
3334 return false; 3350 return false;
3335 } 3351 }
3336 3352
3337 // Didn't click on the label. 3353 // Didn't click on the label.
3338 if (!event.srcElement.classList.contains('filename-label')) 3354 if (!event.srcElement.classList.contains('filename-label'))
3339 return false; 3355 return false;
3340 3356
3341 // Wrong button or using a keyboard modifier. 3357 // Wrong button or using a keyboard modifier.
3342 if (event.button != 0 || event.shiftKey || event.metaKey || event.altKey) { 3358 if (event.button != 0 || event.shiftKey || event.metaKey || event.altKey) {
3343 this.lastLabelClick_ = null; 3359 this.lastLabelClick_ = null;
3344 return false; 3360 return false;
3345 } 3361 }
3346 3362
3347 var now = new Date(); 3363 var now = new Date();
3348 var path = event.srcElement.entry.fullPath; 3364 var index = list.getIndexOfListItem(item);
3349 var lastLabelClick = this.lastLabelClick_; 3365 var lastLabelClick = this.lastLabelClick_;
3350 this.lastLabelClick_ = {path: path, date: now}; 3366 this.lastLabelClick_ = {index: index, date: now};
3351 3367
3352 // Rename already in progress. 3368 // Rename already in progress.
3353 if (this.renameInput_.currentEntry) 3369 if (this.renameInput_.currentEntry)
3354 return false; 3370 return false;
3355 3371
3356 if (lastLabelClick && lastLabelClick.path == path) { 3372 if (lastLabelClick && lastLabelClick.index == index) {
3357 var delay = now - lastLabelClick.date; 3373 var delay = now - lastLabelClick.date;
3358 if (delay > 500 && delay < 2000) { 3374 if (delay > 500 && delay < 2000) {
3359 this.lastLabelClick_ = null; 3375 this.lastLabelClick_ = null;
3360 return true; 3376 return true;
3361 } 3377 }
3362 } 3378 }
3363 3379
3364 return false; 3380 return false;
3365 }; 3381 };
3366 3382
3367 FileManager.prototype.initiateRename_= function(label) { 3383 FileManager.prototype.initiateRename_= function(list, item) {
3384 var label = item.querySelector('.filename-label');
3368 var input = this.renameInput_; 3385 var input = this.renameInput_;
3369 3386
3370 input.value = label.textContent; 3387 input.value = label.textContent;
3371 input.style.top = label.offsetTop + 'px'; 3388 input.style.top = label.offsetTop + 'px';
3372 input.style.left = label.offsetLeft + 'px'; 3389 input.style.left = label.offsetLeft + 'px';
3373 input.style.width = label.clientWidth + 'px'; 3390 input.style.width = label.clientWidth + 'px';
3374 label.parentNode.appendChild(input); 3391 label.parentNode.appendChild(input);
3375 input.focus(); 3392 input.focus();
3376 var selectionEnd = input.value.lastIndexOf('.'); 3393 var selectionEnd = input.value.lastIndexOf('.');
3377 if (selectionEnd == -1) { 3394 if (selectionEnd == -1) {
3378 input.select(); 3395 input.select();
3379 } else { 3396 } else {
3380 input.selectionStart = 0; 3397 input.selectionStart = 0;
3381 input.selectionEnd = selectionEnd; 3398 input.selectionEnd = selectionEnd;
3382 } 3399 }
3383 3400
3384 // This has to be set late in the process so we don't handle spurious 3401 // This has to be set late in the process so we don't handle spurious
3385 // blur events. 3402 // blur events.
3386 input.currentEntry = label.entry; 3403 var index = list.getIndexOfListItem(item);
3404 input.currentEntry = list.dataModel.item(index);
3387 }; 3405 };
3388 3406
3389 FileManager.prototype.onRenameInputKeyDown_ = function(event) { 3407 FileManager.prototype.onRenameInputKeyDown_ = function(event) {
3390 if (!this.renameInput_.currentEntry) 3408 if (!this.renameInput_.currentEntry)
3391 return; 3409 return;
3392 3410
3393 switch (event.keyCode) { 3411 switch (event.keyCode) {
3394 case 27: // Escape 3412 case 27: // Escape
3395 this.cancelRename_(); 3413 this.cancelRename_();
3396 event.preventDefault(); 3414 event.preventDefault();
(...skipping 571 matching lines...) Expand 10 before | Expand all | Expand 10 after
3968 }); 3986 });
3969 }, onError); 3987 }, onError);
3970 3988
3971 function onError(err) { 3989 function onError(err) {
3972 console.log('Error while checking free space: ' + err); 3990 console.log('Error while checking free space: ' + err);
3973 setTimeout(doCheck, 1000 * 60); 3991 setTimeout(doCheck, 1000 * 60);
3974 } 3992 }
3975 } 3993 }
3976 } 3994 }
3977 })(); 3995 })();
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698