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

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

Issue 9802024: Refactoring copy/paste code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Code review fixes. Created 8 years, 9 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 | « no previous file | chrome/browser/resources/file_manager/main.html » ('j') | 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 // 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
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
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
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
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
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 })();
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/file_manager/main.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698