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

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

Issue 8898009: Revert 113804 - [filebrowser] Add left panel with roots. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: 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
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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 metrics.recordEnum('Create', this.dialogType_, 54 metrics.recordEnum('Create', this.dialogType_,
55 [FileManager.DialogType.SELECT_FOLDER, 55 [FileManager.DialogType.SELECT_FOLDER,
56 FileManager.DialogType.SELECT_SAVEAS_FILE, 56 FileManager.DialogType.SELECT_SAVEAS_FILE,
57 FileManager.DialogType.SELECT_OPEN_FILE, 57 FileManager.DialogType.SELECT_OPEN_FILE,
58 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, 58 FileManager.DialogType.SELECT_OPEN_MULTI_FILE,
59 FileManager.DialogType.FULL_PAGE]); 59 FileManager.DialogType.FULL_PAGE]);
60 60
61 // TODO(dgozman): This will be changed to LocaleInfo. 61 // TODO(dgozman): This will be changed to LocaleInfo.
62 this.locale_ = new v8Locale(navigator.language); 62 this.locale_ = new v8Locale(navigator.language);
63 63
64 this.initFileSystem_(); 64 this.resolveRoots_();
65 this.initDom_(); 65 this.initDom_();
66 this.initDialogType_(); 66 this.initDialogType_();
67 this.dialogDom_.style.opacity = '1'; 67 this.dialogDom_.style.opacity = '1';
68 } 68 }
69 69
70 FileManager.prototype = { 70 FileManager.prototype = {
71 __proto__: cr.EventTarget.prototype 71 __proto__: cr.EventTarget.prototype
72 }; 72 };
73 73
74 // Anonymous "namespace". 74 // Anonymous "namespace".
(...skipping 391 matching lines...) Expand 10 before | Expand all | Expand 10 after
466 chrome.fileBrowserPrivate.getStrings(function(strings) { 466 chrome.fileBrowserPrivate.getStrings(function(strings) {
467 localStrings = new LocalStrings(strings); 467 localStrings = new LocalStrings(strings);
468 if (callback) 468 if (callback)
469 callback(); 469 callback();
470 }); 470 });
471 }; 471 };
472 472
473 // Instance methods. 473 // Instance methods.
474 474
475 /** 475 /**
476 * Request local file system, resolve roots and init_ after that. 476 * Request file system and get root entries asynchronously. Invokes init_
477 * @private 477 * when have finished.
478 */ 478 */
479 FileManager.prototype.initFileSystem_ = function() { 479 FileManager.prototype.resolveRoots_ = function(callback) {
480 util.installFileErrorToString(); 480 var rootPaths = ['Downloads', 'removable', 'archive'];
481
481 metrics.startInterval('Load.FileSystem'); 482 metrics.startInterval('Load.FileSystem');
482
483 var self = this; 483 var self = this;
484 484
485 // The list of active mount points to distinct them from other directories. 485 // The list of active mount points to distinct them from other directories.
486 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { 486 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) {
487 self.mountPoints_ = mountPoints; 487 self.mountPoints_ = mountPoints;
488 onDone(); 488 onDone();
489 }); 489 });
490 490
491 function onDone() { 491 function onDone() {
492 if (self.mountPoints_ && self.rootEntries_) 492 if (self.mountPoints_ && self.rootEntries_)
493 self.init_(); 493 self.init_();
494 } 494 }
495 495
496 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { 496 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) {
497 self.filesystem_ = filesystem;
498 util.installFileErrorToString();
499
497 metrics.recordInterval('Load.FileSystem'); 500 metrics.recordInterval('Load.FileSystem');
498 501
499 self.filesystem_ = filesystem; 502 var rootEntries = [];
500 self.resolveRoots_(function(rootEntries) { 503
504 function onAllRootsFound() {
505 metrics.recordInterval('Load.Roots');
501 self.rootEntries_ = rootEntries; 506 self.rootEntries_ = rootEntries;
502 onDone(); 507 onDone();
503 }); 508 }
509
510 function onPathError(path, err) {
511 console.error('Error locating root path: ' + path + ': ' + err);
512 }
513
514 function onEntryFound(entry) {
515 if (entry) {
516 rootEntries.push(entry);
517 } else {
518 onAllRootsFound();
519 }
520 }
521
522 metrics.startInterval('Load.Roots');
523 if (filesystem.name.match(/^chrome-extension_\S+:external/i)) {
524 // We've been handed the local filesystem, whose root directory
525 // cannot be enumerated.
526 util.getDirectories(filesystem.root, {create: false}, rootPaths,
527 onEntryFound, onPathError);
528 } else {
529 util.forEachDirEntry(filesystem.root, onEntryFound);
530 }
504 }); 531 });
505 }; 532 };
506 533
507 /** 534 /**
508 * Get root entries asynchronously. Invokes callback
509 * when have finished.
510 */
511 FileManager.prototype.resolveRoots_ = function(callback) {
512 var rootPaths = [DOWNLOADS_DIRECTORY, ARCHIVE_DIRECTORY,
513 REMOVABLE_DIRECTORY].map(function(s) { return s.substring(1); });
514 var rootEntries = [];
515
516 // The number of entries left to enumerate to get all roots.
517 // When equals to zero, we are done.
518 var entriesToEnumerate = 0;
519 // Entries may be enumerated faster than next one appears, so we have this
520 // guard to not finish too early.
521 var allEntriesFound = false;
522
523 function onPathError(path, err) {
524 console.error('Error locating root path: ' + path + ': ' + err);
525 }
526
527 function onRootFound(root) {
528 if (root) {
529 rootEntries.push(root);
530 } else {
531 entriesToEnumerate--;
532 if (entriesToEnumerate == 0 && allEntriesFound) {
533 metrics.recordInterval('Load.Roots');
534 callback(rootEntries);
535 }
536 }
537 }
538
539 function onEntryFound(entry) {
540 if (entry) {
541 entriesToEnumerate++;
542 var path = entry.fullPath;
543 if (path == ARCHIVE_DIRECTORY || path == REMOVABLE_DIRECTORY) {
544 // All removable devices and mounted archives are considered
545 // roots, and are shown in the sidebar.
546 util.forEachDirEntry(entry, onRootFound);
547 } else {
548 onRootFound(entry);
549 onRootFound(null);
550 }
551 } else {
552 allEntriesFound = true;
553 }
554 }
555
556 metrics.startInterval('Load.Roots');
557 if (this.filesystem_.name.match(/^chrome-extension_\S+:external/i)) {
558 // We've been handed the local filesystem, whose root directory
559 // cannot be enumerated.
560 util.getDirectories(this.filesystem_.root, {create: false}, rootPaths,
561 onEntryFound, onPathError);
562 } else {
563 util.forEachDirEntry(this.filesystem_.root, onEntryFound);
564 }
565 };
566
567 /**
568 * Continue initializing the file manager after resolving roots. 535 * Continue initializing the file manager after resolving roots.
569 */ 536 */
570 FileManager.prototype.init_ = function() { 537 FileManager.prototype.init_ = function() {
571 metrics.startInterval('Load.DOM'); 538 metrics.startInterval('Load.DOM');
572 this.initCommands_();
573 539
574 // TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is 540 // TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is
575 // available in all chrome trunk builds. 541 // available in all chrome trunk builds.
576 if ('createDateTimeFormat' in this.locale_) { 542 if ('createDateTimeFormat' in this.locale_) {
577 this.shortDateFormatter_ = 543 this.shortDateFormatter_ =
578 this.locale_.createDateTimeFormat({'dateType': 'medium'}); 544 this.locale_.createDateTimeFormat({'dateType': 'medium'});
579 } else { 545 } else {
580 this.shortDateFormatter_ = { 546 this.shortDateFormatter_ = {
581 format: function(d) { 547 format: function(d) {
582 return (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear(); 548 return (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 window.addEventListener('unload', this.onUnload_.bind(this)); 586 window.addEventListener('unload', this.onUnload_.bind(this));
621 587
622 this.addEventListener('directory-changed', 588 this.addEventListener('directory-changed',
623 this.onDirectoryChanged_.bind(this)); 589 this.onDirectoryChanged_.bind(this));
624 this.addEventListener('selection-summarized', 590 this.addEventListener('selection-summarized',
625 this.onSelectionSummarized_.bind(this)); 591 this.onSelectionSummarized_.bind(this));
626 592
627 // The list of archives requested to mount. We will show contents once 593 // The list of archives requested to mount. We will show contents once
628 // archive is mounted, but only for mounts from within this filebrowser tab. 594 // archive is mounted, but only for mounts from within this filebrowser tab.
629 this.mountRequests_ = []; 595 this.mountRequests_ = [];
630 this.unmountRequests_ = [];
631 chrome.fileBrowserPrivate.onMountCompleted.addListener( 596 chrome.fileBrowserPrivate.onMountCompleted.addListener(
632 this.onMountCompleted_.bind(this)); 597 this.onMountCompleted_.bind(this));
633 598
634 chrome.fileBrowserPrivate.onFileChanged.addListener( 599 chrome.fileBrowserPrivate.onFileChanged.addListener(
635 this.onFileChanged_.bind(this)); 600 this.onFileChanged_.bind(this));
636 601
637 var self = this; 602 var self = this;
638 603
639 // The list of callbacks to be invoked during the directory rescan after 604 // The list of callbacks to be invoked during the directory rescan after
640 // all paste tasks are complete. 605 // all paste tasks are complete.
641 this.pasteSuccessCallbacks_ = []; 606 this.pasteSuccessCallbacks_ = [];
642 607
608 this.initCommands_();
609
643 this.setupCurrentDirectory_(); 610 this.setupCurrentDirectory_();
644 611
645 this.summarizeSelection_(); 612 this.summarizeSelection_();
646 613
647 this.dataModel_.sort('cachedMtime_', 'desc'); 614 this.dataModel_.sort('cachedMtime_', 'desc');
648 615
649 this.refocus(); 616 this.refocus();
650 617
651 this.createMetadataProvider_(); 618 this.createMetadataProvider_();
652 metrics.recordInterval('Load.DOM'); 619 metrics.recordInterval('Load.DOM');
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 // Cache nodes we'll be manipulating. 658 // Cache nodes we'll be manipulating.
692 this.previewThumbnails_ = 659 this.previewThumbnails_ =
693 this.dialogDom_.querySelector('.preview-thumbnails'); 660 this.dialogDom_.querySelector('.preview-thumbnails');
694 this.previewPanel_ = this.dialogDom_.querySelector('.preview-panel'); 661 this.previewPanel_ = this.dialogDom_.querySelector('.preview-panel');
695 this.previewFilename_ = this.dialogDom_.querySelector('.preview-filename'); 662 this.previewFilename_ = this.dialogDom_.querySelector('.preview-filename');
696 this.previewSummary_ = this.dialogDom_.querySelector('.preview-summary'); 663 this.previewSummary_ = this.dialogDom_.querySelector('.preview-summary');
697 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); 664 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input');
698 this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons'); 665 this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons');
699 this.okButton_ = this.dialogDom_.querySelector('.ok'); 666 this.okButton_ = this.dialogDom_.querySelector('.ok');
700 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); 667 this.cancelButton_ = this.dialogDom_.querySelector('.cancel');
668 this.newFolderButton_ = this.dialogDom_.querySelector('.new-folder');
701 this.deleteButton_ = this.dialogDom_.querySelector('.delete-button'); 669 this.deleteButton_ = this.dialogDom_.querySelector('.delete-button');
702 670
703 this.downloadsWarning_ = 671 this.downloadsWarning_ =
704 this.dialogDom_.querySelector('.downloads-warning'); 672 this.dialogDom_.querySelector('.downloads-warning');
705 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING')); 673 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING'));
706 this.downloadsWarning_.lastElementChild.innerHTML = html; 674 this.downloadsWarning_.lastElementChild.innerHTML = html;
707 var link = this.downloadsWarning_.querySelector('a'); 675 var link = this.downloadsWarning_.querySelector('a');
708 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this)); 676 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this));
709 677
710 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); 678 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
(...skipping 10 matching lines...) Expand all
721 'keyup', this.onFilenameInputKeyUp_.bind(this)); 689 'keyup', this.onFilenameInputKeyUp_.bind(this));
722 this.filenameInput_.addEventListener( 690 this.filenameInput_.addEventListener(
723 'focus', this.onFilenameInputFocus_.bind(this)); 691 'focus', this.onFilenameInputFocus_.bind(this));
724 692
725 var listContainer = this.dialogDom_.querySelector('.list-container'); 693 var listContainer = this.dialogDom_.querySelector('.list-container');
726 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this)); 694 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this));
727 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this)); 695 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this));
728 this.okButton_.addEventListener('click', this.onOk_.bind(this)); 696 this.okButton_.addEventListener('click', this.onOk_.bind(this));
729 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); 697 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this));
730 698
731 this.dialogDom_.querySelector('div.open-sidebar').addEventListener( 699 this.dialogDom_.querySelector('button.new-folder').addEventListener(
732 'click', this.onToggleSidebar_.bind(this)); 700 'click', this.onNewFolderButtonClick_.bind(this));
733 this.dialogDom_.querySelector('div.close-sidebar').addEventListener(
734 'click', this.onToggleSidebar_.bind(this));
735 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container');
736 701
737 this.dialogDom_.querySelector('button.detail-view').addEventListener( 702 this.dialogDom_.querySelector('button.detail-view').addEventListener(
738 'click', this.onDetailViewButtonClick_.bind(this)); 703 'click', this.onDetailViewButtonClick_.bind(this));
739 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener( 704 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener(
740 'click', this.onThumbnailViewButtonClick_.bind(this)); 705 'click', this.onThumbnailViewButtonClick_.bind(this));
741 706
742 this.dialogDom_.ownerDocument.defaultView.addEventListener( 707 this.dialogDom_.ownerDocument.defaultView.addEventListener(
743 'resize', this.onResize_.bind(this)); 708 'resize', this.onResize_.bind(this));
744 709
745 var ary = this.dialogDom_.querySelectorAll('[visibleif]'); 710 var ary = this.dialogDom_.querySelectorAll('[visibleif]');
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 this.selectionModelClass_ = cr.ui.ListSingleSelectionModel; 746 this.selectionModelClass_ = cr.ui.ListSingleSelectionModel;
782 } else { 747 } else {
783 this.selectionModelClass_ = cr.ui.ListSelectionModel; 748 this.selectionModelClass_ = cr.ui.ListSelectionModel;
784 } 749 }
785 750
786 this.dataModel_.addEventListener('splice', 751 this.dataModel_.addEventListener('splice',
787 this.onDataModelSplice_.bind(this)); 752 this.onDataModelSplice_.bind(this));
788 753
789 this.initTable_(); 754 this.initTable_();
790 this.initGrid_(); 755 this.initGrid_();
791 this.initRootsList_();
792 756
793 this.setListType(FileManager.ListType.DETAIL); 757 this.setListType(FileManager.ListType.DETAIL);
794 758
795 this.onResize_(); 759 this.onResize_();
796 760
797 this.textSearchState_ = {text: '', date: new Date()}; 761 this.textSearchState_ = {text: '', date: new Date()};
798 }; 762 };
799 763
800 FileManager.prototype.initRootsList_ = function() {
801 this.rootsList_ = this.dialogDom_.querySelector('.roots-list');
802 cr.ui.List.decorate(this.rootsList_);
803
804 var self = this;
805 this.rootsList_.itemConstructor = function(entry) {
806 return self.renderRoot_(entry);
807 };
808
809 this.rootsList_.selectionModel = new cr.ui.ListSingleSelectionModel();
810 this.rootsList_.selectionModel.addEventListener(
811 'change', this.onRootsSelectionChanged_.bind(this));
812
813 // TODO(dgozman): add "Add a drive" item.
814 this.rootsList_.dataModel = new cr.ui.ArrayDataModel(this.rootEntries_);
815 };
816
817 FileManager.prototype.updateRoots_ = function(opt_changeDirectoryTo) {
818 var self = this;
819 this.resolveRoots_(function(rootEntries) {
820 self.rootEntries_ = rootEntries;
821
822 var dataModel = self.rootsList_.dataModel;
823 var args = [0, dataModel.length].concat(rootEntries);
824 dataModel.splice.apply(dataModel, args);
825
826 self.updateRootsListSelection_();
827
828 if (opt_changeDirectoryTo)
829 self.changeDirectory(opt_changeDirectoryTo);
830 });
831 };
832
833 /** 764 /**
834 * Get the icon type for a given Entry. 765 * Get the icon type for a given Entry.
835 * 766 *
836 * @param {Entry} entry An Entry subclass (FileEntry or DirectoryEntry). 767 * @param {Entry} entry An Entry subclass (FileEntry or DirectoryEntry).
837 * @return {string} 768 * @return {string}
838 */ 769 */
839 FileManager.prototype.getIconType = function(entry) { 770 FileManager.prototype.getIconType = function(entry) {
840 if (!('cachedIconType_' in entry)) 771 if (!('cachedIconType_' in entry))
841 entry.cachedIconType_ = this.computeIconType_(entry); 772 entry.cachedIconType_ = this.computeIconType_(entry);
842 return entry.cachedIconType_; 773 return entry.cachedIconType_;
843 }; 774 };
844 775
845 /** 776 /**
846 * Extract extension from the file name and cat it to to lower case. 777 * Extract extension from the file name and cat it to to lower case.
847 * 778 *
848 * @param {string} name. 779 * @param {string} name.
849 * @return {strin} 780 * @return {strin}
850 */ 781 */
851 function getFileExtension(name) { 782 function getFileExtension(name) {
852 var extIndex = name.lastIndexOf('.'); 783 var extIndex = name.lastIndexOf('.');
853 if (extIndex < 0) 784 if (extIndex < 0)
854 return ''; 785 return '';
855 786
856 return name.substr(extIndex + 1).toLowerCase(); 787 return name.substr(extIndex + 1).toLowerCase();
857 } 788 }
858 789
859 FileManager.prototype.computeIconType_ = function(entry) { 790 FileManager.prototype.computeIconType_ = function(entry) {
860 // TODO(dgozman): refactor this to use proper icons in left panel,
861 // and do not depend on mountPoints.
862 var deviceNumber = this.getDeviceNumber(entry); 791 var deviceNumber = this.getDeviceNumber(entry);
863 if (deviceNumber != undefined) { 792 if (deviceNumber != undefined) {
864 if (this.mountPoints_[deviceNumber].mountCondition == '') 793 if (this.mountPoints_[deviceNumber].mountCondition == '')
865 return 'device'; 794 return 'device';
866 var mountCondition = this.mountPoints_[deviceNumber].mountCondition; 795 var mountCondition = this.mountPoints_[deviceNumber].mountCondition;
867 if (mountCondition == 'unknown_filesystem' || 796 if (mountCondition == 'unknown_filesystem' ||
868 mountCondition == 'unsupported_filesystem') 797 mountCondition == 'unsupported_filesystem')
869 return 'unreadable'; 798 return 'unreadable';
870 } 799 }
871 if (entry.isDirectory) 800 if (entry.isDirectory)
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 !isSystemDirEntry(this.currentDirEntry_)); 1082 !isSystemDirEntry(this.currentDirEntry_));
1154 1083
1155 case 'delete': 1084 case 'delete':
1156 return (// Initialized to the point where we have a current directory 1085 return (// Initialized to the point where we have a current directory
1157 this.currentDirEntry_ && 1086 this.currentDirEntry_ &&
1158 // Rename not in progress. 1087 // Rename not in progress.
1159 !this.renameInput_.currentEntry && 1088 !this.renameInput_.currentEntry &&
1160 !isSystemDirEntry(this.currentDirEntry_)) && 1089 !isSystemDirEntry(this.currentDirEntry_)) &&
1161 this.selection && 1090 this.selection &&
1162 this.selection.totalCount > 0; 1091 this.selection.totalCount > 0;
1163
1164 case 'newfolder':
1165 return this.currentDirEntry_ &&
1166 (this.dialogType_ == 'saveas-file' ||
1167 this.dialogType_ == 'full-page');
1168 } 1092 }
1169 }; 1093 };
1170 1094
1171 FileManager.prototype.updateCommonActionButtons_ = function() { 1095 FileManager.prototype.updateCommonActionButtons_ = function() {
1172 if (this.deleteButton_) 1096 if (this.deleteButton_)
1173 this.deleteButton_.disabled = !this.canExecute_('delete'); 1097 this.deleteButton_.disabled = !this.canExecute_('delete');
1174 }; 1098 };
1175 1099
1176 FileManager.prototype.setListType = function(type) { 1100 FileManager.prototype.setListType = function(type) {
1177 if (type && type == this.listType_) 1101 if (type && type == this.listType_)
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after
1363 leadIndex); 1287 leadIndex);
1364 return; 1288 return;
1365 } 1289 }
1366 1290
1367 this.initiateRename_(label); 1291 this.initiateRename_(label);
1368 return; 1292 return;
1369 1293
1370 case 'delete': 1294 case 'delete':
1371 this.deleteEntries(this.selection.entries); 1295 this.deleteEntries(this.selection.entries);
1372 return; 1296 return;
1373
1374 case 'newfolder':
1375 this.onNewFolderCommand_(event);
1376 return;
1377 } 1297 }
1378 }; 1298 };
1379 1299
1380 /** 1300 /**
1381 * Respond to the back and forward buttons. 1301 * Respond to the back and forward buttons.
1382 */ 1302 */
1383 FileManager.prototype.onPopState_ = function(event) { 1303 FileManager.prototype.onPopState_ = function(event) {
1384 // TODO(serya): We should restore selected items here. 1304 // TODO(serya): We should restore selected items here.
1385 if (this.rootEntries_) 1305 if (this.rootEntries_)
1386 this.setupCurrentDirectory_(); 1306 this.setupCurrentDirectory_();
1387 }; 1307 };
1388 1308
1389 FileManager.prototype.requestResize_ = function(timeout) { 1309 FileManager.prototype.requestResize_ = function(timeout) {
1390 var self = this; 1310 var self = this;
1391 setTimeout(function() { self.onResize_() }, timeout || 0); 1311 setTimeout(function() { self.onResize_() }, timeout || 0);
1392 }; 1312 };
1393 1313
1394 /** 1314 /**
1395 * Resize details and thumb views to fit the new window size. 1315 * Resize details and thumb views to fit the new window size.
1396 */ 1316 */
1397 FileManager.prototype.onResize_ = function() { 1317 FileManager.prototype.onResize_ = function() {
1398 this.table_.style.height = this.grid_.style.height = 1318 this.table_.style.height = this.grid_.style.height =
1399 this.grid_.parentNode.clientHeight + 'px'; 1319 this.grid_.parentNode.clientHeight + 'px';
1320 this.table_.style.width = this.grid_.style.width =
1321 this.grid_.parentNode.clientWidth + 'px';
1322
1323 this.table_.list_.style.width = this.table_.parentNode.clientWidth + 'px';
1400 this.table_.list_.style.height = (this.table_.clientHeight - 1 - 1324 this.table_.list_.style.height = (this.table_.clientHeight - 1 -
1401 this.table_.header_.clientHeight) + 'px'; 1325 this.table_.header_.clientHeight) + 'px';
1402 1326
1403 if (this.listType_ == FileManager.ListType.THUMBNAIL) { 1327 if (this.listType_ == FileManager.ListType.THUMBNAIL) {
1404 var self = this; 1328 var self = this;
1405 setTimeout(function() { 1329 setTimeout(function() {
1406 self.grid_.columns = 0; 1330 self.grid_.columns = 0;
1407 self.grid_.redraw(); 1331 self.grid_.redraw();
1408 }, 0); 1332 }, 0);
1409 } else { 1333 } else {
1410 this.currentList_.redraw(); 1334 this.currentList_.redraw();
1411 } 1335 }
1412
1413 this.rootsList_.style.height =
1414 this.rootsList_.parentNode.clientHeight + 'px';
1415 this.rootsList_.redraw();
1416 }; 1336 };
1417 1337
1418 FileManager.prototype.resolvePath = function( 1338 FileManager.prototype.resolvePath = function(
1419 path, resultCallback, errorCallback) { 1339 path, resultCallback, errorCallback) {
1420 return util.resolvePath(this.filesystem_.root, path, resultCallback, 1340 return util.resolvePath(this.filesystem_.root, path, resultCallback,
1421 errorCallback); 1341 errorCallback);
1422 }; 1342 };
1423 1343
1424 /** 1344 /**
1425 * Restores current directory and may be a selected item after page load (or 1345 * Restores current directory and may be a selected item after page load (or
(...skipping 13 matching lines...) Expand all
1439 this.setupPath_(this.params_.defaultPath); 1359 this.setupPath_(this.params_.defaultPath);
1440 } else { 1360 } else {
1441 this.setupDefaultPath_(); 1361 this.setupDefaultPath_();
1442 } 1362 }
1443 }; 1363 };
1444 1364
1445 FileManager.prototype.setupDefaultPath_ = function() { 1365 FileManager.prototype.setupDefaultPath_ = function() {
1446 // No preset given, find a good place to start. 1366 // No preset given, find a good place to start.
1447 // Check for removable devices, if there are none, go to Downloads. 1367 // Check for removable devices, if there are none, go to Downloads.
1448 var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) { 1368 var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) {
1449 return isParentPath(REMOVABLE_DIRECTORY, rootEntry.fullPath); 1369 return rootEntry.fullPath == REMOVABLE_DIRECTORY;
1450 })[0]; 1370 })[0];
1451 var path = removableDirectoryEntry && removableDirectoryEntry.fullPath || 1371 if (!removableDirectoryEntry) {
1452 DOWNLOADS_DIRECTORY; 1372 this.changeDirectory(DOWNLOADS_DIRECTORY, CD_NO_HISTORY);
1453 this.changeDirectory(path, CD_NO_HISTORY); 1373 return;
1374 }
1375
1376 var foundRemovable = false;
1377 util.forEachDirEntry(removableDirectoryEntry, function(result) {
1378 if (result) {
1379 foundRemovable = true;
1380 } else { // Done enumerating, and we know the answer.
1381 this.changeDirectory(foundRemovable ? '/' : DOWNLOADS_DIRECTORY,
1382 CD_NO_HISTORY);
1383 }
1384 }.bind(this));
1454 }; 1385 };
1455 1386
1456 FileManager.prototype.setupPath_ = function(path) { 1387 FileManager.prototype.setupPath_ = function(path) {
1457 // Split the dirname from the basename. 1388 // Split the dirname from the basename.
1458 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); 1389 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/);
1459 if (!ary) { 1390 if (!ary) {
1460 console.warn('Unable to split default path: ' + path); 1391 console.warn('Unable to split default path: ' + path);
1461 self.changeDirectory('/', CD_NO_HISTORY); 1392 self.changeDirectory('/', CD_NO_HISTORY);
1462 return; 1393 return;
1463 } 1394 }
(...skipping 18 matching lines...) Expand all
1482 1413
1483 // Leaf is an existing file, cd to its parent directory and select it. 1414 // Leaf is an existing file, cd to its parent directory and select it.
1484 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY, function() { 1415 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY, function() {
1485 self.selectEntry(leafEntry.name); 1416 self.selectEntry(leafEntry.name);
1486 }); 1417 });
1487 } 1418 }
1488 1419
1489 function onLeafError(err) { 1420 function onLeafError(err) {
1490 // Set filename first so OK button will update in changeDirectoryEntry. 1421 // Set filename first so OK button will update in changeDirectoryEntry.
1491 self.filenameInput_.value = leafName; 1422 self.filenameInput_.value = leafName;
1492 self.selectDefaultPathInFilenameInput_();
1493 if (err = FileError.NOT_FOUND_ERR) { 1423 if (err = FileError.NOT_FOUND_ERR) {
1494 // Leaf does not exist, it's just a suggested file name. 1424 // Leaf does not exist, it's just a suggested file name.
1495 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY); 1425 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY);
1496 } else { 1426 } else {
1497 console.log('Unexpected error resolving default leaf: ' + err); 1427 console.log('Unexpected error resolving default leaf: ' + err);
1498 self.changeDirectoryEntry('/', CD_NO_HISTORY); 1428 self.changeDirectoryEntry('/', CD_NO_HISTORY);
1499 } 1429 }
1500 } 1430 }
1501 1431
1502 self.resolvePath(path, onLeafFound, onLeafError); 1432 self.resolvePath(path, onLeafFound, onLeafError);
1503 } 1433 }
1504 1434
1505 function onBaseError(err) { 1435 function onBaseError(err) {
1506 // Set filename first so OK button will update in changeDirectory. 1436 // Set filename first so OK button will update in changeDirectory.
1507 self.filenameInput_.value = leafName; 1437 self.filenameInput_.value = leafName;
1508 self.selectDefaultPathInFilenameInput_();
1509 console.log('Unexpected error resolving default base "' + 1438 console.log('Unexpected error resolving default base "' +
1510 baseName + '": ' + err); 1439 baseName + '": ' + err);
1511 self.changeDirectory('/', CD_NO_HISTORY); 1440 self.changeDirectory('/', CD_NO_HISTORY);
1512 } 1441 }
1513 1442
1514 if (baseName) { 1443 if (baseName) {
1515 this.filesystem_.root.getDirectory( 1444 this.filesystem_.root.getDirectory(
1516 baseName, {create: false}, onBaseFound, onBaseError); 1445 baseName, {create: false}, onBaseFound, onBaseError);
1517 } else { 1446 } else {
1518 onBaseFound(this.filesystem_.root); 1447 onBaseFound(this.filesystem_.root);
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
1739 li.className = 'thumbnail-item'; 1668 li.className = 'thumbnail-item';
1740 1669
1741 if (this.showCheckboxes_) 1670 if (this.showCheckboxes_)
1742 li.appendChild(this.renderCheckbox_(entry)); 1671 li.appendChild(this.renderCheckbox_(entry));
1743 1672
1744 li.appendChild(this.renderThumbnailBox_(entry, false)); 1673 li.appendChild(this.renderThumbnailBox_(entry, false));
1745 1674
1746 var div = this.document_.createElement('div'); 1675 var div = this.document_.createElement('div');
1747 div.className = 'filename-label'; 1676 div.className = 'filename-label';
1748 var labelText = entry.name; 1677 var labelText = entry.name;
1678 if (this.currentDirEntry_.name == '')
1679 labelText = this.getLabelForRootPath_(labelText);
1749 1680
1750 div.textContent = labelText; 1681 div.textContent = labelText;
1751 div.entry = entry; 1682 div.entry = entry;
1752 1683
1753 li.appendChild(div); 1684 li.appendChild(div);
1754 1685
1755 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); 1686 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR);
1756 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); 1687 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR);
1757 return li; 1688 return li;
1758 }; 1689 };
1759 1690
1760 /** 1691 /**
1761 * Render the type column of the detail table. 1692 * Render the type column of the detail table.
1762 * 1693 *
1763 * Invoked by cr.ui.Table when a file needs to be rendered. 1694 * Invoked by cr.ui.Table when a file needs to be rendered.
1764 * 1695 *
1765 * @param {Entry} entry The Entry object to render. 1696 * @param {Entry} entry The Entry object to render.
1766 * @param {string} columnId The id of the column to be rendered. 1697 * @param {string} columnId The id of the column to be rendered.
1767 * @param {cr.ui.Table} table The table doing the rendering. 1698 * @param {cr.ui.Table} table The table doing the rendering.
1768 */ 1699 */
1769 FileManager.prototype.renderIconType_ = function(entry, columnId, table) { 1700 FileManager.prototype.renderIconType_ = function(entry, columnId, table) {
1770 var icon = this.document_.createElement('div'); 1701 var icon = this.document_.createElement('div');
1771 icon.className = 'detail-icon'; 1702 icon.className = 'detail-icon';
1772 this.getIconType(entry); 1703 this.getIconType(entry);
1773 icon.setAttribute('iconType', entry.cachedIconType_); 1704 icon.setAttribute('iconType', entry.cachedIconType_);
1774 return icon; 1705 return icon;
1775 }; 1706 };
1776 1707
1777 /** 1708 FileManager.prototype.getLabelForRootPath_ = function(path) {
1778 * Return the localized name for the root. 1709 // This hack lets us localize the top level directories.
1779 * @param {string} path The full path of the root (starting with slash). 1710 if (path == 'Downloads')
1780 * @return {string} The localized name. 1711 return str('DOWNLOADS_DIRECTORY_LABEL');
1781 */
1782 FileManager.prototype.getRootLabel_ = function(path) {
1783 if (path == DOWNLOADS_DIRECTORY)
1784 return str('CHROMEBOOK_DIRECTORY_LABEL');
1785 1712
1786 if (path == ARCHIVE_DIRECTORY) 1713 if (path == 'archive')
1787 return str('ARCHIVE_DIRECTORY_LABEL'); 1714 return str('ARCHIVE_DIRECTORY_LABEL');
1788 if (isParentPath(ARCHIVE_DIRECTORY, path))
1789 return path.substring(ARCHIVE_DIRECTORY.length + 1);
1790 1715
1791 if (path == REMOVABLE_DIRECTORY) 1716 if (path == 'removable')
1792 return str('REMOVABLE_DIRECTORY_LABEL'); 1717 return str('REMOVABLE_DIRECTORY_LABEL');
1793 if (isParentPath(REMOVABLE_DIRECTORY, path))
1794 return path.substring(REMOVABLE_DIRECTORY.length + 1);
1795 1718
1796 return path; 1719 return path || str('ROOT_DIRECTORY_LABEL');
1797 };
1798
1799 FileManager.prototype.getRootIconUrl_ = function(path, opt_small) {
1800 var iconUrl = opt_small ? 'images/chromebook_28x28.png' :
1801 'images/chromebook_24x24.png';
1802 if (isParentPath(REMOVABLE_DIRECTORY, path))
1803 iconUrl = 'images/filetype_device.png';
1804 else if (isParentPath(ARCHIVE_DIRECTORY, path))
1805 iconUrl = 'images/icon_mount_archive_16x16.png';
1806 return chrome.extension.getURL(iconUrl);
1807 };
1808
1809 FileManager.prototype.renderRoot_ = function(entry) {
1810 var li = this.document_.createElement('li');
1811 li.className = 'root-item';
1812
1813 var icon = this.document_.createElement('img');
1814 icon.src = this.getRootIconUrl_(entry.fullPath, false);
1815 li.appendChild(icon);
1816
1817 var div = this.document_.createElement('div');
1818 div.className = 'text';
1819 div.textContent = this.getRootLabel_(entry.fullPath);
1820 li.appendChild(div);
1821
1822 if (isParentPath(REMOVABLE_DIRECTORY, entry.fullPath) ||
1823 isParentPath(ARCHIVE_DIRECTORY, entry.fullPath)) {
1824 var spacer = this.document_.createElement('div');
1825 spacer.className = 'spacer';
1826 li.appendChild(spacer);
1827
1828 var eject = this.document_.createElement('img');
1829 eject.className = 'root-eject';
1830 eject.setAttribute('src', chrome.extension.getURL('images/eject.png'));
1831 eject.addEventListener('click', this.onEjectClick_.bind(this, entry));
1832 li.appendChild(eject);
1833 }
1834
1835 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR);
1836 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR);
1837 return li;
1838 };
1839
1840 /**
1841 * Handler for eject button clicked.
1842 * @param {Entry} entry Entry to eject.
1843 * @param {Event} event The event.
1844 */
1845 FileManager.prototype.onEjectClick_ = function(entry, event) {
1846 this.unmountRequests_.push(entry.toURL());
1847 chrome.fileBrowserPrivate.removeMount(entry.fullPath);
1848 }; 1720 };
1849 1721
1850 /** 1722 /**
1851 * Render the Name column of the detail table. 1723 * Render the Name column of the detail table.
1852 * 1724 *
1853 * Invoked by cr.ui.Table when a file needs to be rendered. 1725 * Invoked by cr.ui.Table when a file needs to be rendered.
1854 * 1726 *
1855 * @param {Entry} entry The Entry object to render. 1727 * @param {Entry} entry The Entry object to render.
1856 * @param {string} columnId The id of the column to be rendered. 1728 * @param {string} columnId The id of the column to be rendered.
1857 * @param {cr.ui.Table} table The table doing the rendering. 1729 * @param {cr.ui.Table} table The table doing the rendering.
1858 */ 1730 */
1859 FileManager.prototype.renderName_ = function(entry, columnId, table) { 1731 FileManager.prototype.renderName_ = function(entry, columnId, table) {
1860 var label = this.document_.createElement('div'); 1732 var label = this.document_.createElement('div');
1861 if (this.showCheckboxes_) 1733 if (this.showCheckboxes_)
1862 label.appendChild(this.renderCheckbox_(entry)); 1734 label.appendChild(this.renderCheckbox_(entry));
1863 label.appendChild(this.renderIconType_(entry, columnId, table)); 1735 label.appendChild(this.renderIconType_(entry, columnId, table));
1864 label.entry = entry; 1736 label.entry = entry;
1865 label.className = 'detail-name'; 1737 label.className = 'detail-name';
1866 label.appendChild(this.document_.createTextNode(entry.name)); 1738 if (this.currentDirEntry_.name == '') {
1739 label.appendChild(this.document_.createTextNode(
1740 this.getLabelForRootPath_(entry.name)));
1741 } else {
1742 label.appendChild(this.document_.createTextNode(entry.name));
1743 }
1744
1867 return label; 1745 return label;
1868 }; 1746 };
1869 1747
1870 /** 1748 /**
1871 * Render the Size column of the detail table. 1749 * Render the Size column of the detail table.
1872 * 1750 *
1873 * @param {Entry} entry The Entry object to render. 1751 * @param {Entry} entry The Entry object to render.
1874 * @param {string} columnId The id of the column to be rendered. 1752 * @param {string} columnId The id of the column to be rendered.
1875 * @param {cr.ui.Table} table The table doing the rendering. 1753 * @param {cr.ui.Table} table The table doing the rendering.
1876 */ 1754 */
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after
2230 task.title = str('GALLERY'); 2108 task.title = str('GALLERY');
2231 task.allTasks = tasksList; 2109 task.allTasks = tasksList;
2232 this.galleryTask_ = task; 2110 this.galleryTask_ = task;
2233 } 2111 }
2234 } 2112 }
2235 this.renderTaskButton_(task); 2113 this.renderTaskButton_(task);
2236 } 2114 }
2237 2115
2238 // These are done in separate functions, as the checks require 2116 // These are done in separate functions, as the checks require
2239 // asynchronous function calls. 2117 // asynchronous function calls.
2118 this.maybeRenderUnmountTask_(selection);
2240 this.maybeRenderFormattingTask_(selection); 2119 this.maybeRenderFormattingTask_(selection);
2241 }; 2120 };
2242 2121
2243 FileManager.prototype.renderTaskButton_ = function(task) { 2122 FileManager.prototype.renderTaskButton_ = function(task) {
2244 var button = this.document_.createElement('button'); 2123 var button = this.document_.createElement('button');
2245 button.addEventListener('click', 2124 button.addEventListener('click',
2246 this.onTaskButtonClicked_.bind(this, task)); 2125 this.onTaskButtonClicked_.bind(this, task));
2247 button.className = 'task-button'; 2126 button.className = 'task-button';
2248 2127
2249 var img = this.document_.createElement('img'); 2128 var img = this.document_.createElement('img');
2250 img.src = task.iconUrl; 2129 img.src = task.iconUrl;
2251 2130
2252 button.appendChild(img); 2131 button.appendChild(img);
2253 var label = this.document_.createElement('div'); 2132 var label = this.document_.createElement('div');
2254 label.appendChild(this.document_.createTextNode(task.title)) 2133 label.appendChild(this.document_.createTextNode(task.title))
2255 button.appendChild(label); 2134 button.appendChild(label);
2256 2135
2257 this.taskButtons_.appendChild(button); 2136 this.taskButtons_.appendChild(button);
2258 }; 2137 };
2259 2138
2260 /** 2139 /**
2140 * Checks whether unmount task should be displayed and if the answer is
2141 * affirmative renders it.
2142 * @param {Object} selection Selected files object.
2143 */
2144 FileManager.prototype.maybeRenderUnmountTask_ = function(selection) {
2145 for (var index = 0; index < selection.urls.length; ++index) {
2146 // Each url should be a mount point.
2147 var path = selection.entries[index].fullPath;
2148 var found = false;
2149 for (var i = 0; i < this.mountPoints_.length; i++) {
2150 var mountPath = this.mountPoints_[i].mountPath;
2151 if (mountPath[0] != '/') {
2152 mountPath = '/' + mountPath;
2153 }
2154 if (mountPath == path && this.mountPoints_[i].mountType == 'file') {
2155 found = true;
2156 break;
2157 }
2158 }
2159 if (!found)
2160 return;
2161 }
2162 this.renderTaskButton_({
2163 taskId: this.getExtensionId_() + '|unmount-archive',
2164 iconUrl:
2165 chrome.extension.getURL('images/icon_unmount_archive_16x16.png'),
2166 title: str('UNMOUNT_ARCHIVE'),
2167 internal: true
2168 });
2169 };
2170
2171 /**
2261 * Checks whether formatting task should be displayed and if the answer is 2172 * Checks whether formatting task should be displayed and if the answer is
2262 * affirmative renders it. Includes asynchronous calls, so it's splitted into 2173 * affirmative renders it. Includes asynchronous calls, so it's splitted into
2263 * three parts. 2174 * three parts.
2264 * @param {Object} selection Selected files object. 2175 * @param {Object} selection Selected files object.
2265 */ 2176 */
2266 FileManager.prototype.maybeRenderFormattingTask_ = function(selection) { 2177 FileManager.prototype.maybeRenderFormattingTask_ = function(selection) {
2267 // Not to make unnecessary getMountPoints() call we doublecheck if there is 2178 // Not to make unnecessary getMountPoints() call we doublecheck if there is
2268 // only one selected entry. 2179 // only one selected entry.
2269 if (selection.entries.length != 1) 2180 if (selection.entries.length != 1)
2270 return; 2181 return;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
2331 chrome.fileBrowserPrivate.executeTask(task.taskId, urls); 2242 chrome.fileBrowserPrivate.executeTask(task.taskId, urls);
2332 }; 2243 };
2333 2244
2334 /** 2245 /**
2335 * Event handler called when some volume was mounted or unmouted. 2246 * Event handler called when some volume was mounted or unmouted.
2336 */ 2247 */
2337 FileManager.prototype.onMountCompleted_ = function(event) { 2248 FileManager.prototype.onMountCompleted_ = function(event) {
2338 var self = this; 2249 var self = this;
2339 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { 2250 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) {
2340 self.mountPoints_ = mountPoints; 2251 self.mountPoints_ = mountPoints;
2341 var changeDirectoryTo = null;
2342
2343 if (event.eventType == 'mount') { 2252 if (event.eventType == 'mount') {
2344 // Mount request finished - remove it. 2253 for (var index = 0; index < self.mountRequests_.length; ++index) {
2345 var index = self.mountRequests_.indexOf(event.sourceUrl); 2254 if (self.mountRequests_[index] == event.sourceUrl) {
2346 if (index != -1) { 2255 self.mountRequests_.splice(index, 1);
2347 self.mountRequests_.splice(index, 1); 2256 if (event.status == 'success') {
2348 // Go to mounted directory, if request was initiated from this tab. 2257 self.changeDirectory(event.mountPath);
2349 if (event.status == 'success') 2258 } else {
2350 changeDirectoryTo = event.mountPath; 2259 // Report mount error.
2260 if (event.mountType == 'file') {
2261 var fileName = event.sourceUrl.substr(
2262 event.sourceUrl.lastIndexOf('/') + 1);
2263 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName,
2264 event.status));
2265 }
2266 }
2267 return;
2268 }
2351 } 2269 }
2352 } 2270 }
2353 2271
2354 if (event.eventType == 'unmount') {
2355 // Unmount request finished - remove it.
2356 var index = self.unmountRequests_.indexOf(event.sourceUrl);
2357 if (index != -1)
2358 self.unmountRequests_.splice(index, 1);
2359 }
2360
2361 if (event.eventType == 'mount' && event.status != 'success' &&
2362 event.mountType == 'file') {
2363 // Report mount error.
2364 var fileName = event.sourceUrl.substr(
2365 event.sourceUrl.lastIndexOf('/') + 1);
2366 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName,
2367 event.status));
2368 }
2369
2370 if (event.eventType == 'unmount' && event.status != 'success') {
2371 // Report unmount error.
2372 // TODO(dgozman): introduce string and show alert here.
2373 }
2374
2375 if (event.eventType == 'unmount' && event.status == 'success' && 2272 if (event.eventType == 'unmount' && event.status == 'success' &&
2376 self.currentDirEntry_ && 2273 self.currentDirEntry_ &&
2377 isParentPath(event.mountPath, self.currentDirEntry_.fullPath)) { 2274 isParentPath(event.mountPath, self.currentDirEntry_.fullPath)) {
2378 changeDirectoryTo = getParentPath(event.mountPath); 2275 self.changeDirectory(getParentPath(event.mountPath));
2276 return;
2379 } 2277 }
2380 2278
2381 // In the case of success, roots are changed and should be rescanned. 2279 var rescanDirectoryNeeded = (event.status == 'success');
2382 if (event.status == 'success') 2280 for (var i = 0; i < mountPoints.length; i++) {
2383 self.updateRoots_(changeDirectoryTo); 2281 if (event.sourceUrl == mountPoints[i].sourceUrl &&
2282 mountPoints[i].mountCondition != '') {
2283 rescanDirectoryNeeded = true;
2284 }
2285 }
2286 // TODO(dgozman): rescan directory, only if it contains mounted points,
2287 // when mounts location will be decided.
2288 if (rescanDirectoryNeeded)
2289 self.rescanDirectory_(null, 300);
2384 }); 2290 });
2385 }; 2291 };
2386 2292
2387 /** 2293 /**
2388 * Event handler called when some internal task should be executed. 2294 * Event handler called when some internal task should be executed.
2389 */ 2295 */
2390 FileManager.prototype.onFileTaskExecute_ = function(id, details) { 2296 FileManager.prototype.onFileTaskExecute_ = function(id, details) {
2391 var urls = details.urls; 2297 var urls = details.urls;
2392 if (id == 'play' || id == 'enqueue') { 2298 if (id == 'play' || id == 'enqueue') {
2393 chrome.fileBrowserPrivate.viewFiles(urls, id); 2299 chrome.fileBrowserPrivate.viewFiles(urls, id);
2394 } else if (id == 'mount-archive') { 2300 } else if (id == 'mount-archive') {
2395 for (var index = 0; index < urls.length; ++index) { 2301 for (var index = 0; index < urls.length; ++index) {
2396 this.mountRequests_.push(urls[index]); 2302 this.mountRequests_.push(urls[index]);
2397 chrome.fileBrowserPrivate.addMount(urls[index], 'file', {}); 2303 chrome.fileBrowserPrivate.addMount(urls[index], 'file', {});
2398 } 2304 }
2305 } else if (id == 'unmount-archive') {
2306 for (var index = 0; index < urls.length; ++index) {
2307 chrome.fileBrowserPrivate.removeMount(urls[index]);
2308 }
2399 } else if (id == 'format-device') { 2309 } else if (id == 'format-device') {
2400 this.confirm.show(str('FORMATTING_WARNING'), function() { 2310 this.confirm.show(str('FORMATTING_WARNING'), function() {
2401 chrome.fileBrowserPrivate.formatDevice(urls[0]); 2311 chrome.fileBrowserPrivate.formatDevice(urls[0]);
2402 }); 2312 });
2403 } else if (id == 'gallery') { 2313 } else if (id == 'gallery') {
2404 // Pass to gallery all possible tasks except the gallery itself. 2314 // Pass to gallery all possible tasks except the gallery itself.
2405 var noGallery = []; 2315 var noGallery = [];
2406 for (var index = 0; index < details.task.allTasks.length; index++) { 2316 for (var index = 0; index < details.task.allTasks.length; index++) {
2407 var task = details.task.allTasks[index]; 2317 var task = details.task.allTasks[index];
2408 if (task.taskId != this.getExtensionId_() + '|gallery') { 2318 if (task.taskId != this.getExtensionId_() + '|gallery') {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
2466 self.metadataProvider_, 2376 self.metadataProvider_,
2467 shareActions, 2377 shareActions,
2468 str); 2378 str);
2469 }; 2379 };
2470 2380
2471 galleryFrame.src = 'js/image_editor/gallery.html'; 2381 galleryFrame.src = 'js/image_editor/gallery.html';
2472 this.dialogDom_.appendChild(galleryFrame); 2382 this.dialogDom_.appendChild(galleryFrame);
2473 galleryFrame.focus(); 2383 galleryFrame.focus();
2474 }; 2384 };
2475 2385
2476 FileManager.prototype.getRootForPath_ = function(path) {
2477 for (var index = 0; index < this.rootEntries_.length; index++) {
2478 if (isParentPath(this.rootEntries_[index].fullPath, path)) {
2479 return index;
2480 }
2481 }
2482 return -1;
2483 };
2484
2485 /** 2386 /**
2486 * Update the breadcrumb display to reflect the current directory. 2387 * Update the breadcrumb display to reflect the current directory.
2487 */ 2388 */
2488 FileManager.prototype.updateBreadcrumbs_ = function() { 2389 FileManager.prototype.updateBreadcrumbs_ = function() {
2489 var bc = this.dialogDom_.querySelector('.breadcrumbs'); 2390 var bc = this.dialogDom_.querySelector('.breadcrumbs');
2490 removeChildren(bc); 2391 removeChildren(bc);
2491 2392
2492 var fullPath = this.currentDirEntry_.fullPath; 2393 var fullPath = this.currentDirEntry_.fullPath.replace(/\/$/, '');
2493 var rootIndex = this.getRootForPath_(fullPath); 2394 var pathNames = fullPath.split('/');
2494 if (rootIndex == -1) { 2395 var path = '';
2495 console.error('Not root for: ' + fullPath);
2496 return;
2497 }
2498 var root = this.rootEntries_[rootIndex];
2499
2500 var icon = this.document_.createElement('img');
2501 icon.className = 'breadcrumb-icon';
2502 icon.setAttribute('src', this.getRootIconUrl_(root.fullPath, true));
2503 bc.appendChild(icon);
2504
2505 var rootPath = root.fullPath;
2506 var relativePath = fullPath.substring(rootPath.length);
2507 var pathNames = relativePath.replace(/\/$/, '').split('/');
2508 if (pathNames[0] == '')
2509 pathNames.splice(0, 1);
2510
2511 // We need a first breadcrumb for root, so placing last name from
2512 // rootPath as first name of relativePath.
2513 var rootPathNames = rootPath.replace(/\/$/, '').split('/');
2514 pathNames.splice(0, 0, rootPathNames[rootPathNames.length - 1]);
2515 rootPathNames.splice(rootPathNames.length - 1, 1);
2516 var path = rootPathNames.join('/') + '/';
2517 2396
2518 for (var i = 0; i < pathNames.length; i++) { 2397 for (var i = 0; i < pathNames.length; i++) {
2519 var pathName = pathNames[i]; 2398 var pathName = pathNames[i];
2520 path += pathName; 2399 path += pathName + '/';
2521 2400
2522 var div = this.document_.createElement('div'); 2401 var div = this.document_.createElement('div');
2523 div.className = 'breadcrumb-path'; 2402 div.className = 'breadcrumb-path';
2524 div.textContent = i == 0 ? this.getRootLabel_(path) : pathName; 2403 if (i <= 1) {
2404 // i == 0: root directory itself, i == 1: the files it contains.
2405 div.textContent = this.getLabelForRootPath_(pathName);
2406 } else {
2407 div.textContent = pathName;
2408 }
2525 2409
2526 path = path + '/';
2527 div.path = path; 2410 div.path = path;
2528 div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); 2411 div.addEventListener('click', this.onBreadcrumbClick_.bind(this));
2529 2412
2530 bc.appendChild(div); 2413 bc.appendChild(div);
2531 2414
2532 if (i == pathNames.length - 1) { 2415 if (i == pathNames.length - 1) {
2533 div.classList.add('breadcrumb-last'); 2416 div.classList.add('breadcrumb-last');
2534 } else { 2417 } else {
2535 var spacer = this.document_.createElement('div'); 2418 var spacer = this.document_.createElement('div');
2536 spacer.className = 'breadcrumb-spacer'; 2419 spacer.className = 'breadcrumb-spacer';
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
2620 2503
2621 FileManager.prototype.selectEntry = function(name) { 2504 FileManager.prototype.selectEntry = function(name) {
2622 for (var i = 0; i < this.dataModel_.length; i++) { 2505 for (var i = 0; i < this.dataModel_.length; i++) {
2623 if (this.dataModel_.item(i).name == name) { 2506 if (this.dataModel_.item(i).name == name) {
2624 this.selectIndex(i); 2507 this.selectIndex(i);
2625 return; 2508 return;
2626 } 2509 }
2627 } 2510 }
2628 }; 2511 };
2629 2512
2630 FileManager.prototype.updateRootsListSelection_ = function() {
2631 if (!this.currentDirEntry_) return;
2632 var index = this.getRootForPath_(this.currentDirEntry_.fullPath);
2633 if (index == -1) {
2634 this.rootsList_.selectionModel.selectedIndex = 0;
2635 } else {
2636 if (this.rootsList_.selectionModel.selectedIndex != index)
2637 this.rootsList_.selectionModel.selectedIndex = index;
2638 }
2639 };
2640
2641 FileManager.prototype.selectIndex = function(index) { 2513 FileManager.prototype.selectIndex = function(index) {
2642 this.currentList_.focus(); 2514 this.currentList_.focus();
2643 if (index >= this.dataModel_.length) 2515 if (index >= this.dataModel_.length)
2644 return; 2516 return;
2645 this.currentList_.selectionModel.selectedIndex = index; 2517 this.currentList_.selectionModel.selectedIndex = index;
2646 this.currentList_.scrollIndexIntoView(index); 2518 this.currentList_.scrollIndexIntoView(index);
2647 }; 2519 };
2648 2520
2649 /** 2521 /**
2650 * Add the file/directory with given name to the current selection. 2522 * Add the file/directory with given name to the current selection.
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
2754 */ 2626 */
2755 FileManager.prototype.changeDirectoryEntry = function(dirEntry, 2627 FileManager.prototype.changeDirectoryEntry = function(dirEntry,
2756 opt_saveHistory, 2628 opt_saveHistory,
2757 opt_action) { 2629 opt_action) {
2758 if (typeof opt_saveHistory == 'undefined') { 2630 if (typeof opt_saveHistory == 'undefined') {
2759 opt_saveHistory = true; 2631 opt_saveHistory = true;
2760 } else { 2632 } else {
2761 opt_saveHistory = !!opt_saveHistory; 2633 opt_saveHistory = !!opt_saveHistory;
2762 } 2634 }
2763 2635
2764 // Some directories are above roots, so we instead show the first root.
2765 // There may be request to change directory above the roots. For example,
2766 // when usb-dirve is removed, we try to change to the parent directory,
2767 // which is REMOVABLE_DIRECTORY.
2768 if (!dirEntry || dirEntry.fullPath == '/' ||
2769 dirEntry.fullPath == REMOVABLE_DIRECTORY ||
2770 dirEntry.fullPath == ARCHIVE_DIRECTORY) {
2771 dirEntry = this.rootEntries_[0] || dirEntry;
2772 }
2773
2774 var action = opt_action || 2636 var action = opt_action ||
2775 (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE ? 2637 (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE ?
2776 undefined : this.selectIndex.bind(this, 0)); 2638 undefined : this.selectIndex.bind(this, 0));
2777 2639
2778 var location = document.location.origin + document.location.pathname + '#' + 2640 var location = document.location.origin + document.location.pathname + '#' +
2779 encodeURI(dirEntry.fullPath); 2641 encodeURI(dirEntry.fullPath);
2780 if (opt_saveHistory) { 2642 if (opt_saveHistory) {
2781 history.pushState(undefined, dirEntry.fullPath, location); 2643 history.pushState(undefined, dirEntry.fullPath, location);
2782 } else if (window.location.hash != location) { 2644 } else if (window.location.hash != location) {
2783 // If the user typed URL manually that is not canonical it would be fixed 2645 // If the user typed URL manually that is not canonical it would be fixed
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after
2998 // then the default action of this click event fires and toggles the 2860 // then the default action of this click event fires and toggles the
2999 // checkbox back off. 2861 // checkbox back off.
3000 // 2862 //
3001 // Since we're going to force checkboxes into the correct state for any 2863 // Since we're going to force checkboxes into the correct state for any
3002 // multi-selection, we can prevent this shift click from toggling the 2864 // multi-selection, we can prevent this shift click from toggling the
3003 // checkbox and avoid the trouble. 2865 // checkbox and avoid the trouble.
3004 event.preventDefault(); 2866 event.preventDefault();
3005 } 2867 }
3006 }; 2868 };
3007 2869
3008 FileManager.prototype.onRootsSelectionChanged_ = function(event) {
3009 var root = this.rootEntries_[this.rootsList_.selectionModel.selectedIndex];
3010 if (!this.currentDirEntry_ ||
3011 !isParentPath(root.fullPath, this.currentDirEntry_.fullPath))
3012 this.changeDirectoryEntry(root);
3013 };
3014
3015 FileManager.prototype.selectDefaultPathInFilenameInput_ = function() {
3016 var input = this.filenameInput_;
3017 input.focus();
3018 var selectionEnd = input.value.lastIndexOf('.');
3019 if (selectionEnd == -1) {
3020 input.select();
3021 } else {
3022 input.selectionStart = 0;
3023 input.selectionEnd = selectionEnd;
3024 }
3025 // Clear, so we never do this again.
3026 this.params_.defaultPath = '';
3027 };
3028
3029 /** 2870 /**
3030 * Update the UI when the selection model changes. 2871 * Update the UI when the selection model changes.
3031 * 2872 *
3032 * @param {cr.Event} event The change event. 2873 * @param {cr.Event} event The change event.
3033 */ 2874 */
3034 FileManager.prototype.onSelectionChanged_ = function(event) { 2875 FileManager.prototype.onSelectionChanged_ = function(event) {
3035 this.summarizeSelection_(); 2876 this.summarizeSelection_();
3036 2877
3037 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { 2878 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) {
3038 // If this is a save-as dialog, copy the selected file into the filename 2879 // If this is a save-as dialog, copy the selected file into the filename
3039 // input text box. 2880 // input text box.
3040 2881
3041 if (this.selection && 2882 if (this.selection &&
3042 this.selection.totalCount == 1 && 2883 this.selection.totalCount == 1 &&
3043 this.selection.entries[0].isFile && 2884 this.selection.entries[0].isFile)
3044 this.filenameInput_.value != this.selection.entries[0].name) {
3045 this.filenameInput_.value = this.selection.entries[0].name; 2885 this.filenameInput_.value = this.selection.entries[0].name;
3046 if (this.params_.defaultPath == this.selection.entries[0].fullPath)
3047 this.selectDefaultPathInFilenameInput_();
3048 }
3049 } 2886 }
3050 2887
3051 this.updateOkButton_(); 2888 this.updateOkButton_();
3052 2889
3053 var self = this; 2890 var self = this;
3054 setTimeout(function() { self.onSelectionChangeComplete_(event) }, 0); 2891 setTimeout(function() { self.onSelectionChangeComplete_(event) }, 0);
3055 }; 2892 };
3056 2893
3057 /** 2894 /**
3058 * Handle selection change related tasks that won't run properly during 2895 * Handle selection change related tasks that won't run properly during
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
3191 * Update the UI when the current directory changes. 3028 * Update the UI when the current directory changes.
3192 * 3029 *
3193 * @param {cr.Event} event The directory-changed event. 3030 * @param {cr.Event} event The directory-changed event.
3194 */ 3031 */
3195 FileManager.prototype.onDirectoryChanged_ = function(event) { 3032 FileManager.prototype.onDirectoryChanged_ = function(event) {
3196 this.updateCommands_(); 3033 this.updateCommands_();
3197 this.updateOkButton_(); 3034 this.updateOkButton_();
3198 3035
3199 this.checkFreeSpace_(this.currentDirEntry_.fullPath); 3036 this.checkFreeSpace_(this.currentDirEntry_.fullPath);
3200 3037
3201 // TODO(dgozman): title may be better than this. 3038 // New folder should never be enabled in the root or media/ directories.
3039 this.newFolderButton_.disabled = isSystemDirEntry(this.currentDirEntry_);
3040
3202 this.document_.title = this.currentDirEntry_.fullPath; 3041 this.document_.title = this.currentDirEntry_.fullPath;
3203 3042
3204 var self = this; 3043 var self = this;
3205 3044
3206 if (this.subscribedOnDirectoryChanges_) { 3045 if (this.subscribedOnDirectoryChanges_) {
3207 chrome.fileBrowserPrivate.removeFileWatch(event.previousDirEntry.toURL(), 3046 chrome.fileBrowserPrivate.removeFileWatch(event.previousDirEntry.toURL(),
3208 function(result) { 3047 function(result) {
3209 if (!result) { 3048 if (!result) {
3210 console.log('Failed to remove file watch'); 3049 console.log('Failed to remove file watch');
3211 } 3050 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
3285 // Updated when a user clicks on the label of a file, used to detect 3124 // Updated when a user clicks on the label of a file, used to detect
3286 // when a click is eligible to trigger a rename. Can be null, or 3125 // when a click is eligible to trigger a rename. Can be null, or
3287 // an object with 'path' and 'date' properties. 3126 // an object with 'path' and 'date' properties.
3288 this.lastLabelClick_ = null; 3127 this.lastLabelClick_ = null;
3289 3128
3290 // Clear the table first. 3129 // Clear the table first.
3291 this.dataModel_.splice(0, this.dataModel_.length); 3130 this.dataModel_.splice(0, this.dataModel_.length);
3292 this.currentList_.selectionModel.clear(); 3131 this.currentList_.selectionModel.clear();
3293 3132
3294 this.updateBreadcrumbs_(); 3133 this.updateBreadcrumbs_();
3295 this.updateRootsListSelection_();
3296 3134
3297 // Add current request to pending result list 3135 if (this.currentDirEntry_.fullPath != '/') {
3298 this.pendingRescanQueue_.push({ 3136 // Add current request to pending result list
3299 onSuccess:opt_callback, 3137 this.pendingRescanQueue_.push({
3300 onError:opt_onError 3138 onSuccess:opt_callback,
3301 }); 3139 onError:opt_onError
3140 });
3302 3141
3303 if (this.rescanRunning_) 3142 if (this.rescanRunning_)
3304 return; 3143 return;
3305 3144
3306 this.rescanRunning_ = true; 3145 this.rescanRunning_ = true;
3307 3146
3308 // The current list of callbacks is saved and reset. Subsequent 3147 // The current list of callbacks is saved and reset. Subsequent
3309 // calls to rescanDirectory_ while we're still pending will be 3148 // calls to rescanDirectory_ while we're still pending will be
3310 // saved and will cause an additional rescan to happen after a delay. 3149 // saved and will cause an additional rescan to happen after a delay.
3311 var callbacks = this.pendingRescanQueue_; 3150 var callbacks = this.pendingRescanQueue_;
3312 3151
3313 this.pendingRescanQueue_ = []; 3152 this.pendingRescanQueue_ = [];
3314 3153
3315 var self = this; 3154 var self = this;
3316 var reader; 3155 var reader;
3317 3156
3318 function onError() { 3157 function onError() {
3319 if (self.pendingRescanQueue_.length > 0) {
3320 setTimeout(self.rescanDirectory_.bind(self),
3321 SIMULTANEOUS_RESCAN_INTERVAL);
3322 }
3323
3324 self.rescanRunning_ = false;
3325
3326 for (var i= 0; i < callbacks.length; i++) {
3327 if (callbacks[i].onError)
3328 try {
3329 callbacks[i].onError();
3330 } catch (ex) {
3331 console.error('Caught exception while notifying about error: ' +
3332 name, ex);
3333 }
3334 }
3335 }
3336
3337 function onReadSome(entries) {
3338 if (entries.length == 0) {
3339 metrics.recordInterval('DirectoryScan');
3340 if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) {
3341 metrics.recordMediumCount("DownloadsCount", self.dataModel_.length);
3342 }
3343
3344 if (self.pendingRescanQueue_.length > 0) { 3158 if (self.pendingRescanQueue_.length > 0) {
3345 setTimeout(self.rescanDirectory_.bind(self), 3159 setTimeout(self.rescanDirectory_.bind(self),
3346 SIMULTANEOUS_RESCAN_INTERVAL); 3160 SIMULTANEOUS_RESCAN_INTERVAL);
3347 } 3161 }
3348 3162
3349 self.rescanRunning_ = false; 3163 self.rescanRunning_ = false;
3164
3350 for (var i= 0; i < callbacks.length; i++) { 3165 for (var i= 0; i < callbacks.length; i++) {
3351 if (callbacks[i].onSuccess) 3166 if (callbacks[i].onError)
3352 try { 3167 try {
3353 callbacks[i].onSuccess(); 3168 callbacks[i].onError();
3354 } catch (ex) { 3169 } catch (ex) {
3355 console.error('Caught exception while notifying about error: ' + 3170 console.error('Caught exception while notifying about error: ' +
3356 name, ex); 3171 name, ex);
3357 } 3172 }
3358 } 3173 }
3359
3360 return;
3361 } 3174 }
3362 3175
3363 // Splice takes the to-be-spliced-in array as individual parameters, 3176 function onReadSome(entries) {
3364 // rather than as an array, so we need to perform some acrobatics... 3177 if (entries.length == 0) {
3365 var spliceArgs = [].slice.call(entries); 3178 metrics.recordInterval('DirectoryScan');
3179 if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) {
3180 metrics.recordMediumCount("DownloadsCount", self.dataModel_.length);
3181 }
3366 3182
3367 // Hide files that start with a dot ('.'). 3183 if (self.pendingRescanQueue_.length > 0) {
3368 // TODO(rginda): User should be able to override this. Support for other 3184 setTimeout(self.rescanDirectory_.bind(self),
3369 // commonly hidden patterns might be nice too. 3185 SIMULTANEOUS_RESCAN_INTERVAL);
3370 if (self.filterFiles_) { 3186 }
3371 spliceArgs = spliceArgs.filter(function(e) {
3372 return e.name.substr(0, 1) != '.';
3373 });
3374 }
3375 3187
3376 self.prefetchCacheForSorting_(spliceArgs, function() { 3188 self.rescanRunning_ = false;
3377 spliceArgs.unshift(0, 0); // index, deleteCount 3189 for (var i= 0; i < callbacks.length; i++) {
3378 self.dataModel_.splice.apply(self.dataModel_, spliceArgs); 3190 if (callbacks[i].onSuccess)
3191 try {
3192 callbacks[i].onSuccess();
3193 } catch (ex) {
3194 console.error('Caught exception while notifying about error: ' +
3195 name, ex);
3196 }
3197 }
3379 3198
3380 // Keep reading until entries.length is 0. 3199 return;
3381 reader.readEntries(onReadSome, onError); 3200 }
3382 });
3383 };
3384 3201
3385 metrics.startInterval('DirectoryScan'); 3202 // Splice takes the to-be-spliced-in array as individual parameters,
3203 // rather than as an array, so we need to perform some acrobatics...
3204 var spliceArgs = [].slice.call(entries);
3386 3205
3387 // If not the root directory, just read the contents. 3206 // Hide files that start with a dot ('.').
3388 reader = this.currentDirEntry_.createReader(); 3207 // TODO(rginda): User should be able to override this. Support for other
3389 reader.readEntries(onReadSome, onError); 3208 // commonly hidden patterns might be nice too.
3209 if (self.filterFiles_) {
3210 spliceArgs = spliceArgs.filter(function(e) {
3211 return e.name.substr(0, 1) != '.';
3212 });
3213 }
3214
3215 self.prefetchCacheForSorting_(spliceArgs, function() {
3216 spliceArgs.unshift(0, 0); // index, deleteCount
3217 self.dataModel_.splice.apply(self.dataModel_, spliceArgs);
3218
3219 // Keep reading until entries.length is 0.
3220 reader.readEntries(onReadSome, onError);
3221 });
3222 };
3223
3224 metrics.startInterval('DirectoryScan');
3225
3226 // If not the root directory, just read the contents.
3227 reader = this.currentDirEntry_.createReader();
3228 reader.readEntries(onReadSome, onError);
3229 return;
3230 }
3231
3232 // Otherwise, use the provided list of root subdirectories, since the
3233 // real local filesystem root directory (the one we use outside the
3234 // harness) can't be enumerated yet.
3235 var spliceArgs = [].slice.call(this.rootEntries_);
3236 spliceArgs.unshift(0, 0); // index, deleteCount
3237 this.dataModel_.splice.apply(this.dataModel_, spliceArgs);
3238
3239 if (opt_callback)
3240 opt_callback();
3390 }; 3241 };
3391 3242
3392 FileManager.prototype.prefetchCacheForSorting_ = function(entries, callback) { 3243 FileManager.prototype.prefetchCacheForSorting_ = function(entries, callback) {
3393 var field = this.dataModel_.sortStatus.field; 3244 var field = this.dataModel_.sortStatus.field;
3394 if (field) { 3245 if (field) {
3395 this.prepareSortEntries_(entries, field, callback); 3246 this.prepareSortEntries_(entries, field, callback);
3396 } else { 3247 } else {
3397 callback(); 3248 callback();
3398 return; 3249 return;
3399 } 3250 }
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after
3633 var selectionEnd = input.value.lastIndexOf('.'); 3484 var selectionEnd = input.value.lastIndexOf('.');
3634 if (selectionEnd == -1) { 3485 if (selectionEnd == -1) {
3635 input.select(); 3486 input.select();
3636 } else { 3487 } else {
3637 input.selectionStart = 0; 3488 input.selectionStart = 0;
3638 input.selectionEnd = selectionEnd; 3489 input.selectionEnd = selectionEnd;
3639 } 3490 }
3640 }, 0); 3491 }, 0);
3641 }; 3492 };
3642 3493
3643 FileManager.prototype.onToggleSidebar_ = function(event) { 3494 FileManager.prototype.onNewFolderButtonClick_ = function(event) {
3644 if (this.dialogContainer_.hasAttribute('sidebar')) {
3645 this.dialogContainer_.removeAttribute('sidebar');
3646 } else {
3647 this.dialogContainer_.setAttribute('sidebar', 'sidebar');
3648 }
3649 // TODO(dgozman): make table header css-resizable.
3650 setTimeout(this.onResize_.bind(this), 300);
3651 };
3652
3653 FileManager.prototype.onNewFolderCommand_ = function(event) {
3654 var self = this; 3495 var self = this;
3655 3496
3656 function onNameSelected(name) { 3497 function onNameSelected(name) {
3657 var valid = self.validateFileName_(name, function() { 3498 var valid = self.validateFileName_(name, function() {
3658 promptForName(name); 3499 promptForName(name);
3659 }); 3500 });
3660 3501
3661 if (!valid) { 3502 if (!valid) {
3662 // Validation failed. User will be prompted for a new name after they 3503 // Validation failed. User will be prompted for a new name after they
3663 // dismiss the validation error dialog. 3504 // dismiss the validation error dialog.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
3772 this.dialogType_ != FileManager.SELECT_FOLDER) { 3613 this.dialogType_ != FileManager.SELECT_FOLDER) {
3773 event.preventDefault(); 3614 event.preventDefault();
3774 this.onDirectoryAction(this.selection.entries[0]); 3615 this.onDirectoryAction(this.selection.entries[0]);
3775 } else if (!this.okButton_.disabled) { 3616 } else if (!this.okButton_.disabled) {
3776 event.preventDefault(); 3617 event.preventDefault();
3777 this.onOk_(); 3618 this.onOk_();
3778 } 3619 }
3779 break; 3620 break;
3780 3621
3781 case 32: // Ctrl-Space => New Folder. 3622 case 32: // Ctrl-Space => New Folder.
3782 if ((this.dialogType_ == 'saveas-file' || 3623 if (this.newFolderButton_.style.display != 'none' && event.ctrlKey) {
3783 this.dialogType_ == 'full-page') && event.ctrlKey) {
3784 event.preventDefault(); 3624 event.preventDefault();
3785 this.onNewFolderCommand_(); 3625 this.onNewFolderButtonClick_();
3786 } 3626 }
3787 break; 3627 break;
3788 3628
3789 case 88: // Ctrl-X => Cut. 3629 case 88: // Ctrl-X => Cut.
3790 this.updateCommands_(); 3630 this.updateCommands_();
3791 if (!this.commands_['cut'].disabled) { 3631 if (!this.commands_['cut'].disabled) {
3792 event.preventDefault(); 3632 event.preventDefault();
3793 this.commands_['cut'].execute(); 3633 this.commands_['cut'].execute();
3794 } 3634 }
3795 break; 3635 break;
(...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after
4128 }); 3968 });
4129 }, onError); 3969 }, onError);
4130 3970
4131 function onError(err) { 3971 function onError(err) {
4132 console.log('Error while checking free space: ' + err); 3972 console.log('Error while checking free space: ' + err);
4133 setTimeout(doCheck, 1000 * 60); 3973 setTimeout(doCheck, 1000 * 60);
4134 } 3974 }
4135 } 3975 }
4136 } 3976 }
4137 })(); 3977 })();
OLDNEW
« no previous file with comments | « chrome/browser/resources/file_manager/css/file_manager.css ('k') | chrome/browser/resources/file_manager/js/harness.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698