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 // 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 | 7 |
8 /** | 8 /** |
9 * FileManager constructor. | 9 * FileManager constructor. |
10 * | 10 * |
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
642 cr.ui.Grid.decorate(this.grid_); | 642 cr.ui.Grid.decorate(this.grid_); |
643 | 643 |
644 this.downloadsWarning_ = | 644 this.downloadsWarning_ = |
645 this.dialogDom_.querySelector('.downloads-warning'); | 645 this.dialogDom_.querySelector('.downloads-warning'); |
646 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING')); | 646 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING')); |
647 this.downloadsWarning_.lastElementChild.innerHTML = html; | 647 this.downloadsWarning_.lastElementChild.innerHTML = html; |
648 var link = this.downloadsWarning_.querySelector('a'); | 648 var link = this.downloadsWarning_.querySelector('a'); |
649 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this)); | 649 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this)); |
650 | 650 |
651 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); | 651 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); |
652 this.document_.addEventListener('copy', | 652 this.document_.addEventListener('copy', this.onCopy_.bind(this)); |
653 this.onCopy_.bind(this)); | 653 this.document_.addEventListener('beforecopy', |
| 654 this.onBeforeCopy_.bind(this)); |
654 // Disable the default browser context menu. | 655 // Disable the default browser context menu. |
655 this.document_.addEventListener('contextmenu', | 656 this.document_.addEventListener('contextmenu', |
656 function (e) { e.preventDefault() }); | 657 function (e) { e.preventDefault() }); |
657 | 658 |
658 // We need to store a reference to the function returned by bind. Later, in | 659 this.document_.addEventListener('paste', this.onPaste_.bind(this)); |
659 // canPaste function, we need to temporarily remove this event handler and | 660 // HACK(serya): 'paste'/'beforepaste' must be used. |
660 // use another 'paste' event handler to check the state of system clipboard. | 661 // But 'beforepaste' is apparently broken. |
661 this.onPasteBound_ = this.onPaste_.bind(this); | 662 var iframe = this.document_.querySelector('#command-dispatcher'); |
662 this.document_.addEventListener('paste', this.onPasteBound_); | 663 this.commandProbbingDoc_ = iframe.contentDocument; |
663 | 664 this.commandProbbingDoc_.addEventListener('paste', |
664 // In pasteFromClipboard function, we need to reset system clipboard after | 665 this.onBeforePaste_.bind(this)); |
665 // 'cut' and 'paste' command sequence. The clipboardData.clearData doesn't | 666 this.document_.addEventListener('cut', this.onCut_.bind(this)); |
666 // seem to work. We reset the system clipboard in another 'cut' event | 667 this.document_.addEventListener('beforecut', this.onBeforeCut_.bind(this)); |
667 // handler as a workaround. This reference is used to temporarily remove | |
668 // 'cut' event handler as well. | |
669 this.onCutBound_ = this.onCut_.bind(this); | |
670 this.document_.addEventListener('cut', this.onCutBound_); | |
671 | 668 |
672 this.renameInput_ = this.document_.createElement('input'); | 669 this.renameInput_ = this.document_.createElement('input'); |
673 this.renameInput_.className = 'rename'; | 670 this.renameInput_.className = 'rename'; |
674 | 671 |
675 this.renameInput_.addEventListener( | 672 this.renameInput_.addEventListener( |
676 'keydown', this.onRenameInputKeyDown_.bind(this)); | 673 'keydown', this.onRenameInputKeyDown_.bind(this)); |
677 this.renameInput_.addEventListener( | 674 this.renameInput_.addEventListener( |
678 'blur', this.onRenameInputBlur_.bind(this)); | 675 'blur', this.onRenameInputBlur_.bind(this)); |
679 | 676 |
680 this.filenameInput_.addEventListener( | 677 this.filenameInput_.addEventListener( |
681 'keyup', this.onFilenameInputKeyUp_.bind(this)); | 678 'keyup', this.onFilenameInputKeyUp_.bind(this)); |
682 this.filenameInput_.addEventListener( | 679 this.filenameInput_.addEventListener( |
683 'focus', this.onFilenameInputFocus_.bind(this)); | 680 'focus', this.onFilenameInputFocus_.bind(this)); |
684 | 681 |
685 var listContainer = this.dialogDom_.querySelector('.list-container'); | 682 var listContainer = this.dialogDom_.querySelector('.list-container'); |
686 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this)); | 683 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this)); |
687 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this)); | 684 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this)); |
688 this.okButton_.addEventListener('click', this.onOk_.bind(this)); | 685 this.okButton_.addEventListener('click', this.onOk_.bind(this)); |
689 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); | 686 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); |
690 | 687 |
691 this.dialogDom_.querySelector('div.open-sidebar').addEventListener( | 688 this.dialogDom_.querySelector('div.open-sidebar').addEventListener( |
692 'click', this.onToggleSidebar_.bind(this)); | 689 'click', this.onToggleSidebar_.bind(this)); |
693 this.dialogDom_.querySelector('div.open-sidebar').addEventListener( | 690 this.dialogDom_.querySelector('div.open-sidebar').addEventListener( |
694 'keypress', this.onToggleSidebarPress_.bind(this)); | 691 'keypress', this.onToggleSidebarPress_.bind(this)); |
695 this.dialogDom_.querySelector('div.close-sidebar').addEventListener( | 692 this.dialogDom_.querySelector('div.close-sidebar').addEventListener( |
696 'click', this.onToggleSidebar_.bind(this)); | 693 'click', this.onToggleSidebar_.bind(this)); |
697 this.dialogDom_.querySelector('div.close-sidebar').addEventListener( | 694 this.dialogDom_.querySelector('div.close-sidebar').addEventListener( |
698 'keypress', this.onToggleSidebarPress_.bind(this)); | 695 'keypress', this.onToggleSidebarPress_.bind(this)); |
699 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); | 696 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); |
700 | |
701 this.dialogDom_.querySelector('button.detail-view').addEventListener( | 697 this.dialogDom_.querySelector('button.detail-view').addEventListener( |
702 'click', this.onDetailViewButtonClick_.bind(this)); | 698 'click', this.onDetailViewButtonClick_.bind(this)); |
703 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener( | 699 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener( |
704 'click', this.onThumbnailViewButtonClick_.bind(this)); | 700 'click', this.onThumbnailViewButtonClick_.bind(this)); |
705 | 701 |
706 cr.ui.ComboButton.decorate(this.taskItems_); | 702 cr.ui.ComboButton.decorate(this.taskItems_); |
707 this.taskItems_.addEventListener('select', | 703 this.taskItems_.addEventListener('select', |
708 this.onTaskItemClicked_.bind(this)); | 704 this.onTaskItemClicked_.bind(this)); |
709 | 705 |
710 this.dialogDom_.ownerDocument.defaultView.addEventListener( | 706 this.dialogDom_.ownerDocument.defaultView.addEventListener( |
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 }; | 1082 }; |
1087 | 1083 |
1088 /** | 1084 /** |
1089 * Force the canExecute events to be dispatched. | 1085 * Force the canExecute events to be dispatched. |
1090 */ | 1086 */ |
1091 FileManager.prototype.updateCommands_ = function() { | 1087 FileManager.prototype.updateCommands_ = function() { |
1092 for (var key in this.commands_) | 1088 for (var key in this.commands_) |
1093 this.commands_[key].disabled = !this.canExecute_(key); | 1089 this.commands_[key].disabled = !this.canExecute_(key); |
1094 }; | 1090 }; |
1095 | 1091 |
1096 FileManager.prototype.canPaste_ = function(readonly) { | |
1097 /** | |
1098 * Fire a paste event and check the "paste" command can be executed. | |
1099 * | |
1100 * We need to peek the content in system clipboard. Only cut/copy/paste | |
1101 * events contain clipboard data. So we need to fire a paste event and then | |
1102 * peek the system clipboard immediately. | |
1103 * | |
1104 * @return {boolean} True if "paste" command can be executed for current | |
1105 * directory. | |
1106 */ | |
1107 | |
1108 var canPaste = false; | |
1109 var clipboardCanPaste = function(event) { | |
1110 event.preventDefault(); | |
1111 // Here we need to use lower case as clipboardData.types return lower | |
1112 // case DomStringList. | |
1113 if (event.clipboardData && | |
1114 event.clipboardData.types && | |
1115 event.clipboardData.types.indexOf('fs/iscut') != -1) | |
1116 canPaste = true; | |
1117 }; | |
1118 | |
1119 this.document_.removeEventListener('paste', this.onPasteBound_); | |
1120 this.document_.addEventListener('paste', clipboardCanPaste); | |
1121 this.document_.execCommand('paste'); | |
1122 this.document_.removeEventListener('paste', clipboardCanPaste); | |
1123 this.document_.addEventListener('paste', this.onPasteBound_); | |
1124 return canPaste && !readonly; | |
1125 }; | |
1126 | |
1127 /** | 1092 /** |
1128 * @param {string} commandId Command identifier. | 1093 * @param {string} commandId Command identifier. |
1129 * @return {boolean} True if the command can be executed for current | 1094 * @return {boolean} True if the command can be executed for current |
1130 * selection. | 1095 * selection. |
1131 */ | 1096 */ |
1132 FileManager.prototype.canExecute_ = function(commandId) { | 1097 FileManager.prototype.canExecute_ = function(commandId) { |
1133 var readonly = this.directoryModel_.readonly; | 1098 var readonly = this.directoryModel_.readonly; |
1134 var path = this.directoryModel_.currentEntry.fullPath; | 1099 var path = this.directoryModel_.currentEntry.fullPath; |
1135 switch (commandId) { | 1100 switch (commandId) { |
| 1101 case 'copy': |
1136 case 'cut': | 1102 case 'cut': |
1137 return !readonly && | 1103 return this.document_.queryCommandEnabled(commandId); |
1138 this.selection && | |
1139 this.selection.totalCount > 0; | |
1140 | |
1141 case 'copy': | |
1142 return path != '/' && | |
1143 this.selection && | |
1144 this.selection.totalCount > 0; | |
1145 | 1104 |
1146 case 'paste': | 1105 case 'paste': |
1147 return this.canPaste_(readonly); | 1106 // HACK(serya): return this.document_.queryCommandEnabled('paste') |
| 1107 // should be used. |
| 1108 this.commandProbbingDoc_.execCommand('paste'); |
| 1109 return !this.commands_.paste.disabled; |
1148 | 1110 |
1149 case 'rename': | 1111 case 'rename': |
1150 return (// Initialized to the point where we have a current directory | 1112 return (// Initialized to the point where we have a current directory |
1151 !readonly && | 1113 !readonly && |
1152 // Rename not in progress. | 1114 // Rename not in progress. |
1153 !this.isRenamingInProgress() && | 1115 !this.isRenamingInProgress() && |
1154 // Only one file selected. | 1116 // Only one file selected. |
1155 this.selection && | 1117 this.selection && |
1156 this.selection.totalCount == 1); | 1118 this.selection.totalCount == 1); |
1157 | 1119 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1303 cr.ui.contextMenuHandler.setContextMenu(this.table_.querySelector('.list'), | 1265 cr.ui.contextMenuHandler.setContextMenu(this.table_.querySelector('.list'), |
1304 this.fileContextMenu_); | 1266 this.fileContextMenu_); |
1305 | 1267 |
1306 this.table_.addEventListener('mousedown', | 1268 this.table_.addEventListener('mousedown', |
1307 this.onGridOrTableMouseDown_.bind(this)); | 1269 this.onGridOrTableMouseDown_.bind(this)); |
1308 this.setupDragAndDrop_(this.table_.list); | 1270 this.setupDragAndDrop_(this.table_.list); |
1309 }; | 1271 }; |
1310 | 1272 |
1311 FileManager.prototype.setupDragAndDrop_ = function(list) { | 1273 FileManager.prototype.setupDragAndDrop_ = function(list) { |
1312 list.addEventListener('dragstart', this.onDragStart_.bind(this)); | 1274 list.addEventListener('dragstart', this.onDragStart_.bind(this)); |
| 1275 list.addEventListener('dragend', this.onDragEnd_.bind(this)); |
| 1276 list.addEventListener('dragover', this.onDragOver_.bind(this)); |
| 1277 list.addEventListener('drop', this.onDrop_.bind(this)); |
1313 }; | 1278 }; |
1314 | 1279 |
1315 FileManager.prototype.onDragStart_ = function(event) { | 1280 FileManager.prototype.onDragStart_ = function(event) { |
1316 var dt = event.dataTransfer; | 1281 var dt = event.dataTransfer; |
1317 var container = this.document_.querySelector('#drag-image-container'); | 1282 var container = this.document_.querySelector('#drag-image-container'); |
1318 container.textContent = ''; | 1283 var length = this.selection.dragNodes.length; |
1319 for (var i = 0; i < this.selection.dragNodes.length; i++) { | 1284 for (var i = 0; i < length; i++) { |
1320 var listItem = this.selection.dragNodes[i]; | 1285 var listItem = this.selection.dragNodes[i]; |
1321 listItem.selected = true; | 1286 listItem.selected = true; |
| 1287 listItem.style.zIndex = length - i; |
1322 container.appendChild(listItem); | 1288 container.appendChild(listItem); |
1323 } | 1289 } |
1324 | 1290 |
1325 this.cutOrCopyToClipboard_(dt, false); | 1291 this.cutOrCopyToClipboard_(dt, false); |
1326 | 1292 |
1327 dt.setDragImage(container, 0, 0); | 1293 dt.setDragImage(container, 0, 0); |
1328 dt.effectAllowed = 'copyMove'; | 1294 dt.effectAllowed = 'copyMove'; |
1329 }; | 1295 }; |
1330 | 1296 |
| 1297 FileManager.prototype.onDragEnd_ = function(event) { |
| 1298 var container = this.document_.querySelector('#drag-image-container'); |
| 1299 container.textContent = ''; |
| 1300 }; |
| 1301 |
| 1302 FileManager.prototype.onDragOver_ = function(event) { |
| 1303 if (this.canPasteOrDrop_(event.dataTransfer)) { |
| 1304 event.preventDefault(); |
| 1305 } |
| 1306 }; |
| 1307 |
| 1308 FileManager.prototype.onDrop_ = function(event) { |
| 1309 if (!this.canPasteOrDrop_(event.dataTransfer)) |
| 1310 return; |
| 1311 event.preventDefault(); |
| 1312 this.pasteFromClipboard_(event.dataTransfer); |
| 1313 }; |
| 1314 |
1331 FileManager.prototype.initButter_ = function() { | 1315 FileManager.prototype.initButter_ = function() { |
1332 var self = this; | 1316 var self = this; |
1333 var progress = this.copyManager_.getProgress(); | 1317 var progress = this.copyManager_.getProgress(); |
1334 | 1318 |
1335 var options = {progress: progress.percentage, actions:{}}; | 1319 var options = {progress: progress.percentage, actions:{}}; |
1336 options.actions[str('CANCEL_LABEL')] = function cancelPaste() { | 1320 options.actions[str('CANCEL_LABEL')] = function cancelPaste() { |
1337 self.copyManager_.requestCancel(); | 1321 self.copyManager_.requestCancel(); |
1338 }; | 1322 }; |
1339 this.showButter(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), | 1323 this.showButter(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), |
1340 options); | 1324 options); |
(...skipping 1808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3149 clipboard.setData('fs/directories', directories); | 3133 clipboard.setData('fs/directories', directories); |
3150 clipboard.setData('fs/files', files); | 3134 clipboard.setData('fs/files', files); |
3151 | 3135 |
3152 var files = this.selection.files; | 3136 var files = this.selection.files; |
3153 for(var i = 0; i < files.length; i++) { | 3137 for(var i = 0; i < files.length; i++) { |
3154 clipboard.items.add(files[i]); | 3138 clipboard.items.add(files[i]); |
3155 } | 3139 } |
3156 } | 3140 } |
3157 | 3141 |
3158 FileManager.prototype.onCopy_ = function(event) { | 3142 FileManager.prototype.onCopy_ = function(event) { |
3159 if (!this.selection || this.selection.totalCount == 0 || | 3143 if (this.document_.activeElement.tagName == 'INPUT' || |
3160 this.document_.activeElement.tagName == 'INPUT') | 3144 !this.canCopyOrDrag_()) { |
3161 return; | 3145 return; |
3162 | 3146 } |
3163 event.preventDefault(); | 3147 event.preventDefault(); |
3164 this.cutOrCopyToClipboard_(event.clipboardData, false); | 3148 this.cutOrCopyToClipboard_(event.clipboardData, false); |
3165 | |
3166 this.blinkSelection(); | 3149 this.blinkSelection(); |
3167 }; | 3150 }; |
3168 | 3151 |
| 3152 FileManager.prototype.onBeforeCopy_ = function(event) { |
| 3153 // queryCommandEnabled returns true if event.returnValue is false. |
| 3154 event.returnValue = !this.canCopyOrDrag_(); |
| 3155 }; |
| 3156 |
| 3157 FileManager.prototype.canCopyOrDrag_ = function() { |
| 3158 return this.selection && this.selection.totalCount > 0; |
| 3159 }; |
| 3160 |
3169 FileManager.prototype.onCut_ = function(event) { | 3161 FileManager.prototype.onCut_ = function(event) { |
3170 if (!this.selection || this.selection.totalCount == 0 || | 3162 if (!this.document_.activeElement.tagName == 'INPUT' || |
3171 this.commands_['cut'].disabled || | 3163 this.canCutOrDrag_()) { |
3172 this.document_.activeElement.tagName == 'INPUT') | |
3173 return; | 3164 return; |
3174 | 3165 } |
3175 event.preventDefault(); | 3166 event.preventDefault(); |
3176 this.cutOrCopyToClipboard_(event.clipboardData, true); | 3167 this.cutOrCopyToClipboard_(event.clipboardData, true); |
3177 | 3168 |
3178 this.blinkSelection(); | 3169 this.blinkSelection(); |
3179 }; | 3170 }; |
3180 | 3171 |
| 3172 FileManager.prototype.onBeforeCut_ = function(event) { |
| 3173 // queryCommandEnabled returns true if event.returnValue is false. |
| 3174 event.returnValue = !this.canCutOrDrag_(); |
| 3175 }; |
| 3176 |
| 3177 FileManager.prototype.canCutOrDrag_ = function() { |
| 3178 var ro = this.directoryModel_.readonly; |
| 3179 return !ro && this.selection && this.selection.totalCount > 0; |
| 3180 }; |
| 3181 |
3181 FileManager.prototype.onPaste_ = function(event) { | 3182 FileManager.prototype.onPaste_ = function(event) { |
3182 // Check that the data copied by ourselves. | 3183 if (this.document_.activeElement.tagName == 'INPUT' || |
3183 if (!event.clipboardData.getData('fs/isCut') || | 3184 !this.canPasteOrDrop_(event.clipboardData)) { |
3184 this.document_.activeElement.tagName == 'INPUT') | |
3185 return; | 3185 return; |
| 3186 } |
3186 event.preventDefault(); | 3187 event.preventDefault(); |
3187 this.pasteFromClipboard_(event.clipboardData); | 3188 this.pasteFromClipboard_(event.clipboardData); |
3188 }; | 3189 }; |
3189 | 3190 |
| 3191 FileManager.prototype.onBeforePaste_ = function(event) { |
| 3192 // TODO(serya) should be: |
| 3193 // event.returnValue = !this.canPasteOrDrop_(event.clipboardData); |
| 3194 this.commands_.paste.disabled = |
| 3195 !this.canPasteOrDrop_(event.clipboardData); |
| 3196 }; |
| 3197 |
| 3198 FileManager.prototype.canPasteOrDrop_ = function(clipboardData) { |
| 3199 var ro = this.directoryModel_.readonly; |
| 3200 return !ro && !!clipboardData.getData('fs/isCut'); |
| 3201 }; |
| 3202 |
3190 /** | 3203 /** |
3191 * Queue up a file copy operation based on the current system clipboard. | 3204 * Queue up a file copy operation based on the current system clipboard. |
3192 */ | 3205 */ |
3193 FileManager.prototype.pasteFromClipboard_ = function(clipboard) { | 3206 FileManager.prototype.pasteFromClipboard_ = function(clipboard) { |
3194 var operationInfo = { | 3207 var operationInfo = { |
3195 isCut: clipboard.getData('fs/isCut'), | 3208 isCut: clipboard.getData('fs/isCut'), |
3196 isOnGData: clipboard.getData('fs/isOnGData'), | 3209 isOnGData: clipboard.getData('fs/isOnGData'), |
3197 sourceDir: clipboard.getData('fs/sourceDir'), | 3210 sourceDir: clipboard.getData('fs/sourceDir'), |
3198 directories: clipboard.getData('fs/directories'), | 3211 directories: clipboard.getData('fs/directories'), |
3199 files: clipboard.getData('fs/files') | 3212 files: clipboard.getData('fs/files') |
(...skipping 1232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4432 }); | 4445 }); |
4433 }, onError); | 4446 }, onError); |
4434 | 4447 |
4435 function onError(err) { | 4448 function onError(err) { |
4436 console.log('Error while checking free space: ' + err); | 4449 console.log('Error while checking free space: ' + err); |
4437 setTimeout(doCheck, 1000 * 60); | 4450 setTimeout(doCheck, 1000 * 60); |
4438 } | 4451 } |
4439 } | 4452 } |
4440 } | 4453 } |
4441 })(); | 4454 })(); |
OLD | NEW |