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) { | 1092 FileManager.prototype.canPaste_ = function(clipboard) { |
1097 /** | 1093 return clipboard && |
1098 * Fire a paste event and check the "paste" command can be executed. | 1094 clipboard.types && |
1099 * | 1095 clipboard.types.indexOf('fs/iscut') != -1; |
dgozman
2012/03/28 08:28:14
This method is not used.
SeRya
2012/03/28 08:43:07
Done.
| |
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 }; | 1096 }; |
1126 | 1097 |
1127 /** | 1098 /** |
1128 * @param {string} commandId Command identifier. | 1099 * @param {string} commandId Command identifier. |
1129 * @return {boolean} True if the command can be executed for current | 1100 * @return {boolean} True if the command can be executed for current |
1130 * selection. | 1101 * selection. |
1131 */ | 1102 */ |
1132 FileManager.prototype.canExecute_ = function(commandId) { | 1103 FileManager.prototype.canExecute_ = function(commandId) { |
1133 var readonly = this.directoryModel_.readonly; | 1104 var readonly = this.directoryModel_.readonly; |
1134 var path = this.directoryModel_.currentEntry.fullPath; | 1105 var path = this.directoryModel_.currentEntry.fullPath; |
1135 switch (commandId) { | 1106 switch (commandId) { |
1107 case 'copy': | |
1136 case 'cut': | 1108 case 'cut': |
1137 return !readonly && | 1109 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 | 1110 |
1146 case 'paste': | 1111 case 'paste': |
1147 return this.canPaste_(readonly); | 1112 // HACK(serya): return this.document_.queryCommandEnabled('paste') |
1113 // should be used. | |
1114 this.commandProbbingDoc_.execCommand('paste'); | |
1115 return !this.commands_.paste.disabled; | |
1148 | 1116 |
1149 case 'rename': | 1117 case 'rename': |
1150 return (// Initialized to the point where we have a current directory | 1118 return (// Initialized to the point where we have a current directory |
1151 !readonly && | 1119 !readonly && |
1152 // Rename not in progress. | 1120 // Rename not in progress. |
1153 !this.isRenamingInProgress() && | 1121 !this.isRenamingInProgress() && |
1154 // Only one file selected. | 1122 // Only one file selected. |
1155 this.selection && | 1123 this.selection && |
1156 this.selection.totalCount == 1); | 1124 this.selection.totalCount == 1); |
1157 | 1125 |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1303 cr.ui.contextMenuHandler.setContextMenu(this.table_.querySelector('.list'), | 1271 cr.ui.contextMenuHandler.setContextMenu(this.table_.querySelector('.list'), |
1304 this.fileContextMenu_); | 1272 this.fileContextMenu_); |
1305 | 1273 |
1306 this.table_.addEventListener('mousedown', | 1274 this.table_.addEventListener('mousedown', |
1307 this.onGridOrTableMouseDown_.bind(this)); | 1275 this.onGridOrTableMouseDown_.bind(this)); |
1308 this.setupDragAndDrop_(this.table_.list); | 1276 this.setupDragAndDrop_(this.table_.list); |
1309 }; | 1277 }; |
1310 | 1278 |
1311 FileManager.prototype.setupDragAndDrop_ = function(list) { | 1279 FileManager.prototype.setupDragAndDrop_ = function(list) { |
1312 list.addEventListener('dragstart', this.onDragStart_.bind(this)); | 1280 list.addEventListener('dragstart', this.onDragStart_.bind(this)); |
1281 list.addEventListener('dragend', this.onDragEnd_.bind(this)); | |
1282 list.addEventListener('dragover', this.onDragOver_.bind(this)); | |
1283 list.addEventListener('drop', this.onDrop_.bind(this)); | |
1313 }; | 1284 }; |
1314 | 1285 |
1315 FileManager.prototype.onDragStart_ = function(event) { | 1286 FileManager.prototype.onDragStart_ = function(event) { |
1316 var dt = event.dataTransfer; | 1287 var dt = event.dataTransfer; |
1317 var container = this.document_.querySelector('#drag-image-container'); | 1288 var container = this.document_.querySelector('#drag-image-container'); |
1318 container.textContent = ''; | 1289 var length = this.selection.dragNodes.length; |
1319 for (var i = 0; i < this.selection.dragNodes.length; i++) { | 1290 for (var i = 0; i < length; i++) { |
1320 var listItem = this.selection.dragNodes[i]; | 1291 var listItem = this.selection.dragNodes[i]; |
1321 listItem.selected = true; | 1292 listItem.selected = true; |
1293 listItem.style.zIndex = length - i; | |
1322 container.appendChild(listItem); | 1294 container.appendChild(listItem); |
1323 } | 1295 } |
1324 | 1296 |
1325 this.cutOrCopyToClipboard_(dt, false); | 1297 this.cutOrCopyToClipboard_(dt, false); |
1326 | 1298 |
1327 dt.setDragImage(container, 0, 0); | 1299 dt.setDragImage(container, 0, 0); |
1328 dt.effectAllowed = 'copyMove'; | 1300 dt.effectAllowed = 'copyMove'; |
1329 }; | 1301 }; |
1330 | 1302 |
1303 FileManager.prototype.onDragEnd_ = function(event) { | |
1304 var container = this.document_.querySelector('#drag-image-container'); | |
1305 container.textContent = ''; | |
1306 }; | |
1307 | |
1308 FileManager.prototype.onDragOver_ = function(event) { | |
1309 if (this.canPasteOrDrop_(event.dataTransfer)) { | |
1310 event.preventDefault(); | |
dgozman
2012/03/28 08:28:14
It would be good to show cursor 'no-drop' otherwis
SeRya
2012/03/28 08:43:07
Let's do it later.
| |
1311 } | |
1312 }; | |
1313 | |
1314 FileManager.prototype.onDrop_ = function(event) { | |
1315 if (!this.canPasteOrDrop_(event.dataTransfer)) | |
1316 return; | |
1317 event.preventDefault(); | |
1318 this.pasteFromClipboard_(event.dataTransfer); | |
1319 }; | |
1320 | |
1331 FileManager.prototype.initButter_ = function() { | 1321 FileManager.prototype.initButter_ = function() { |
1332 var self = this; | 1322 var self = this; |
1333 var progress = this.copyManager_.getProgress(); | 1323 var progress = this.copyManager_.getProgress(); |
1334 | 1324 |
1335 var options = {progress: progress.percentage, actions:{}}; | 1325 var options = {progress: progress.percentage, actions:{}}; |
1336 options.actions[str('CANCEL_LABEL')] = function cancelPaste() { | 1326 options.actions[str('CANCEL_LABEL')] = function cancelPaste() { |
1337 self.copyManager_.requestCancel(); | 1327 self.copyManager_.requestCancel(); |
1338 }; | 1328 }; |
1339 this.showButter(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), | 1329 this.showButter(strf('PASTE_ITEMS_REMAINING', progress.pendingItems), |
1340 options); | 1330 options); |
(...skipping 1808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3149 clipboard.setData('fs/directories', directories); | 3139 clipboard.setData('fs/directories', directories); |
3150 clipboard.setData('fs/files', files); | 3140 clipboard.setData('fs/files', files); |
3151 | 3141 |
3152 var files = this.selection.files; | 3142 var files = this.selection.files; |
3153 for(var i = 0; i < files.length; i++) { | 3143 for(var i = 0; i < files.length; i++) { |
3154 clipboard.items.add(files[i]); | 3144 clipboard.items.add(files[i]); |
3155 } | 3145 } |
3156 } | 3146 } |
3157 | 3147 |
3158 FileManager.prototype.onCopy_ = function(event) { | 3148 FileManager.prototype.onCopy_ = function(event) { |
3159 if (!this.selection || this.selection.totalCount == 0 || | 3149 if (this.document_.activeElement.tagName == 'INPUT' || |
3160 this.document_.activeElement.tagName == 'INPUT') | 3150 !this.canCopyOrDrag_()) { |
3161 return; | 3151 return; |
3162 | 3152 } |
3163 event.preventDefault(); | 3153 event.preventDefault(); |
3164 this.cutOrCopyToClipboard_(event.clipboardData, false); | 3154 this.cutOrCopyToClipboard_(event.clipboardData, false); |
3165 | |
3166 this.blinkSelection(); | 3155 this.blinkSelection(); |
3167 }; | 3156 }; |
3168 | 3157 |
3158 FileManager.prototype.onBeforeCopy_ = function(event) { | |
3159 event.returnValue = !this.canCopyOrDrag_(); | |
dgozman
2012/03/28 08:28:14
Please, add a comment that returnValue==false init
SeRya
2012/03/28 08:43:07
Done.
| |
3160 }; | |
3161 | |
3162 FileManager.prototype.canCopyOrDrag_ = function() { | |
3163 return this.selection && this.selection.totalCount > 0; | |
3164 }; | |
3165 | |
3169 FileManager.prototype.onCut_ = function(event) { | 3166 FileManager.prototype.onCut_ = function(event) { |
3170 if (!this.selection || this.selection.totalCount == 0 || | 3167 if (!this.document_.activeElement.tagName == 'INPUT' || |
3171 this.commands_['cut'].disabled || | 3168 this.canCutOrDrag_()) { |
3172 this.document_.activeElement.tagName == 'INPUT') | |
3173 return; | 3169 return; |
3174 | 3170 } |
3175 event.preventDefault(); | 3171 event.preventDefault(); |
3176 this.cutOrCopyToClipboard_(event.clipboardData, true); | 3172 this.cutOrCopyToClipboard_(event.clipboardData, true); |
3177 | 3173 |
3178 this.blinkSelection(); | 3174 this.blinkSelection(); |
3179 }; | 3175 }; |
3180 | 3176 |
3177 FileManager.prototype.onBeforeCut_ = function(event) { | |
3178 event.returnValue = !this.canCutOrDrag_(); | |
3179 }; | |
3180 | |
3181 FileManager.prototype.canCutOrDrag_ = function() { | |
3182 var ro = this.directoryModel_.readonly; | |
3183 return !ro && this.selection && this.selection.totalCount > 0; | |
3184 }; | |
3185 | |
3181 FileManager.prototype.onPaste_ = function(event) { | 3186 FileManager.prototype.onPaste_ = function(event) { |
3182 // Check that the data copied by ourselves. | 3187 if (this.document_.activeElement.tagName == 'INPUT' || |
3183 if (!event.clipboardData.getData('fs/isCut') || | 3188 !this.canPasteOrDrop_(event.clipboardData)) { |
3184 this.document_.activeElement.tagName == 'INPUT') | |
3185 return; | 3189 return; |
3190 } | |
3186 event.preventDefault(); | 3191 event.preventDefault(); |
3187 this.pasteFromClipboard_(event.clipboardData); | 3192 this.pasteFromClipboard_(event.clipboardData); |
3188 }; | 3193 }; |
3189 | 3194 |
3195 FileManager.prototype.onBeforePaste_ = function(event) { | |
3196 // TODO(serya) should be: | |
3197 // event.returnValue = !this.canPasteOrDrop_(event.clipboardData); | |
3198 this.commands_.paste.disabled = | |
3199 !this.canPasteOrDrop_(event.clipboardData); | |
3200 }; | |
3201 | |
3202 FileManager.prototype.canPasteOrDrop_ = function(clipboardData) { | |
3203 var ro = this.directoryModel_.readonly; | |
3204 return !ro && !!clipboardData.getData('fs/isCut'); | |
3205 }; | |
3206 | |
3190 /** | 3207 /** |
3191 * Queue up a file copy operation based on the current system clipboard. | 3208 * Queue up a file copy operation based on the current system clipboard. |
3192 */ | 3209 */ |
3193 FileManager.prototype.pasteFromClipboard_ = function(clipboard) { | 3210 FileManager.prototype.pasteFromClipboard_ = function(clipboard) { |
3194 var operationInfo = { | 3211 var operationInfo = { |
3195 isCut: clipboard.getData('fs/isCut'), | 3212 isCut: clipboard.getData('fs/isCut'), |
3196 isOnGData: clipboard.getData('fs/isOnGData'), | 3213 isOnGData: clipboard.getData('fs/isOnGData'), |
3197 sourceDir: clipboard.getData('fs/sourceDir'), | 3214 sourceDir: clipboard.getData('fs/sourceDir'), |
3198 directories: clipboard.getData('fs/directories'), | 3215 directories: clipboard.getData('fs/directories'), |
3199 files: clipboard.getData('fs/files') | 3216 files: clipboard.getData('fs/files') |
(...skipping 1232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4432 }); | 4449 }); |
4433 }, onError); | 4450 }, onError); |
4434 | 4451 |
4435 function onError(err) { | 4452 function onError(err) { |
4436 console.log('Error while checking free space: ' + err); | 4453 console.log('Error while checking free space: ' + err); |
4437 setTimeout(doCheck, 1000 * 60); | 4454 setTimeout(doCheck, 1000 * 60); |
4438 } | 4455 } |
4439 } | 4456 } |
4440 } | 4457 } |
4441 })(); | 4458 })(); |
OLD | NEW |