Chromium Code Reviews| 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 // 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 })(); |
| OLD | NEW |