OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Setting the src of an img to an empty string can crash the browser, so we | 5 // Setting the src of an img to an empty string can crash the browser, so we |
6 // use an empty 1x1 gif instead. | 6 // use an empty 1x1 gif instead. |
7 const EMPTY_IMAGE_URI = 'data:image/gif;base64,' | 7 const EMPTY_IMAGE_URI = 'data:image/gif;base64,' |
8 + 'R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D'; | 8 + 'R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D'; |
9 | 9 |
10 var g_slideshow_data = null; | 10 var g_slideshow_data = null; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
56 metrics.recordEnum('Create', this.dialogType_, | 56 metrics.recordEnum('Create', this.dialogType_, |
57 [FileManager.DialogType.SELECT_FOLDER, | 57 [FileManager.DialogType.SELECT_FOLDER, |
58 FileManager.DialogType.SELECT_SAVEAS_FILE, | 58 FileManager.DialogType.SELECT_SAVEAS_FILE, |
59 FileManager.DialogType.SELECT_OPEN_FILE, | 59 FileManager.DialogType.SELECT_OPEN_FILE, |
60 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, | 60 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, |
61 FileManager.DialogType.FULL_PAGE]); | 61 FileManager.DialogType.FULL_PAGE]); |
62 | 62 |
63 // TODO(dgozman): This will be changed to LocaleInfo. | 63 // TODO(dgozman): This will be changed to LocaleInfo. |
64 this.locale_ = new v8Locale(navigator.language); | 64 this.locale_ = new v8Locale(navigator.language); |
65 | 65 |
66 this.resolveRoots_(); | 66 this.initFileSystem_(); |
67 this.initDom_(); | 67 this.initDom_(); |
68 this.initDialogType_(); | 68 this.initDialogType_(); |
69 this.dialogDom_.style.opacity = '1'; | 69 this.dialogDom_.style.opacity = '1'; |
70 } | 70 } |
71 | 71 |
72 FileManager.prototype = { | 72 FileManager.prototype = { |
73 __proto__: cr.EventTarget.prototype | 73 __proto__: cr.EventTarget.prototype |
74 }; | 74 }; |
75 | 75 |
76 // Anonymous "namespace". | 76 // Anonymous "namespace". |
(...skipping 387 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
464 chrome.fileBrowserPrivate.getStrings(function(strings) { | 464 chrome.fileBrowserPrivate.getStrings(function(strings) { |
465 localStrings = new LocalStrings(strings); | 465 localStrings = new LocalStrings(strings); |
466 if (callback) | 466 if (callback) |
467 callback(); | 467 callback(); |
468 }); | 468 }); |
469 }; | 469 }; |
470 | 470 |
471 // Instance methods. | 471 // Instance methods. |
472 | 472 |
473 /** | 473 /** |
474 * Request file system and get root entries asynchronously. Invokes init_ | 474 * Request local file system, resolve roots and init_ after that. |
arv (Not doing code reviews)
2011/11/30 18:21:12
missing @private?
dgozman
2011/12/01 10:13:04
Done.
| |
475 * when have finished. | |
476 */ | 475 */ |
477 FileManager.prototype.resolveRoots_ = function(callback) { | 476 FileManager.prototype.initFileSystem_ = function() { |
478 var rootPaths = ['Downloads', 'removable', 'archive']; | 477 util.installFileErrorToString(); |
478 metrics.startInterval('Load.FileSystem'); | |
479 | 479 |
480 metrics.startInterval('Load.FileSystem'); | |
481 var self = this; | 480 var self = this; |
482 | 481 |
483 // The list of active mount points to distinct them from other directories. | 482 // The list of active mount points to distinct them from other directories. |
484 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { | 483 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { |
485 self.mountPoints_ = mountPoints; | 484 self.mountPoints_ = mountPoints; |
486 onDone(); | 485 onDone(); |
487 }); | 486 }); |
488 | 487 |
489 function onDone() { | 488 function onDone() { |
490 if (self.mountPoints_ && self.rootEntries_) | 489 if (self.mountPoints_ && self.rootEntries_) |
491 self.init_(); | 490 self.init_(); |
492 } | 491 } |
493 | 492 |
494 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { | 493 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { |
495 self.filesystem_ = filesystem; | |
496 util.installFileErrorToString(); | |
497 | |
498 metrics.recordTime('Load.FileSystem'); | 494 metrics.recordTime('Load.FileSystem'); |
499 | 495 |
500 var rootEntries = []; | 496 self.filesystem_ = filesystem; |
501 | 497 self.resolveRoots_(function(rootEntries) { |
502 function onAllRootsFound() { | |
503 metrics.recordTime('Load.Roots'); | |
504 self.rootEntries_ = rootEntries; | 498 self.rootEntries_ = rootEntries; |
505 onDone(); | 499 onDone(); |
506 } | 500 }); |
507 | |
508 function onPathError(path, err) { | |
509 console.error('Error locating root path: ' + path + ': ' + err); | |
510 } | |
511 | |
512 function onEntryFound(entry) { | |
513 if (entry) { | |
514 rootEntries.push(entry); | |
515 } else { | |
516 onAllRootsFound(); | |
517 } | |
518 } | |
519 | |
520 metrics.startInterval('Load.Roots'); | |
521 if (filesystem.name.match(/^chrome-extension_\S+:external/i)) { | |
522 // We've been handed the local filesystem, whose root directory | |
523 // cannot be enumerated. | |
524 util.getDirectories(filesystem.root, {create: false}, rootPaths, | |
525 onEntryFound, onPathError); | |
526 } else { | |
527 util.forEachDirEntry(filesystem.root, onEntryFound); | |
528 } | |
529 }); | 501 }); |
530 }; | 502 }; |
531 | 503 |
532 /** | 504 /** |
505 * Get root entries asynchronously. Invokes callback | |
506 * when have finished. | |
507 */ | |
508 FileManager.prototype.resolveRoots_ = function(callback) { | |
509 var rootPaths = [DOWNLOADS_DIRECTORY, ARCHIVE_DIRECTORY, | |
510 REMOVABLE_DIRECTORY].map(function(s) { return s.substring(1); }); | |
511 var rootEntries = []; | |
512 | |
513 // The number of entries left to enumerate to get all roots. | |
514 // When equals to zero, we are done. | |
515 var entriesToEnumerate = 0; | |
516 // Entries may be enumerated faster than next one appears, so we have this | |
517 // guard to not finish too early. | |
518 var allEntriesFound = false; | |
519 | |
520 function onPathError(path, err) { | |
521 console.error('Error locating root path: ' + path + ': ' + err); | |
522 } | |
523 | |
524 function onRootFound(root) { | |
525 if (root) { | |
526 rootEntries.push(root); | |
527 } else { | |
528 entriesToEnumerate--; | |
529 if (entriesToEnumerate == 0 && allEntriesFound) { | |
530 metrics.recordTime('Load.Roots'); | |
531 callback(rootEntries); | |
532 } | |
533 } | |
534 } | |
535 | |
536 function onEntryFound(entry) { | |
537 if (entry) { | |
538 entriesToEnumerate++; | |
539 var path = entry.fullPath; | |
540 if (path == ARCHIVE_DIRECTORY || path == REMOVABLE_DIRECTORY) { | |
541 // All removable devices and mounted archives are considered | |
542 // roots, and are shown in the sidebar. | |
543 util.forEachDirEntry(entry, onRootFound); | |
544 } else { | |
545 onRootFound(entry); | |
546 onRootFound(null); | |
547 } | |
548 } else { | |
549 allEntriesFound = true; | |
550 } | |
551 } | |
552 | |
553 metrics.startInterval('Load.Roots'); | |
554 if (this.filesystem_.name.match(/^chrome-extension_\S+:external/i)) { | |
555 // We've been handed the local filesystem, whose root directory | |
556 // cannot be enumerated. | |
557 util.getDirectories(this.filesystem_.root, {create: false}, rootPaths, | |
558 onEntryFound, onPathError); | |
559 } else { | |
560 util.forEachDirEntry(this.filesystem_.root, onEntryFound); | |
561 } | |
562 }; | |
563 | |
564 /** | |
533 * Continue initializing the file manager after resolving roots. | 565 * Continue initializing the file manager after resolving roots. |
534 */ | 566 */ |
535 FileManager.prototype.init_ = function() { | 567 FileManager.prototype.init_ = function() { |
536 metrics.startInterval('Load.DOM'); | 568 metrics.startInterval('Load.DOM'); |
569 this.initCommands_(); | |
537 | 570 |
538 // TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is | 571 // TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is |
539 // available in all chrome trunk builds. | 572 // available in all chrome trunk builds. |
540 if ('createDateTimeFormat' in this.locale_) { | 573 if ('createDateTimeFormat' in this.locale_) { |
541 this.shortDateFormatter_ = | 574 this.shortDateFormatter_ = |
542 this.locale_.createDateTimeFormat({'dateType': 'medium'}); | 575 this.locale_.createDateTimeFormat({'dateType': 'medium'}); |
543 } else { | 576 } else { |
544 this.shortDateFormatter_ = { | 577 this.shortDateFormatter_ = { |
545 format: function(d) { | 578 format: function(d) { |
546 return (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear(); | 579 return (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear(); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
584 window.addEventListener('unload', this.onUnload_.bind(this)); | 617 window.addEventListener('unload', this.onUnload_.bind(this)); |
585 | 618 |
586 this.addEventListener('directory-changed', | 619 this.addEventListener('directory-changed', |
587 this.onDirectoryChanged_.bind(this)); | 620 this.onDirectoryChanged_.bind(this)); |
588 this.addEventListener('selection-summarized', | 621 this.addEventListener('selection-summarized', |
589 this.onSelectionSummarized_.bind(this)); | 622 this.onSelectionSummarized_.bind(this)); |
590 | 623 |
591 // The list of archives requested to mount. We will show contents once | 624 // The list of archives requested to mount. We will show contents once |
592 // archive is mounted, but only for mounts from within this filebrowser tab. | 625 // archive is mounted, but only for mounts from within this filebrowser tab. |
593 this.mountRequests_ = []; | 626 this.mountRequests_ = []; |
627 this.unmountRequests_ = []; | |
594 chrome.fileBrowserPrivate.onMountCompleted.addListener( | 628 chrome.fileBrowserPrivate.onMountCompleted.addListener( |
595 this.onMountCompleted_.bind(this)); | 629 this.onMountCompleted_.bind(this)); |
596 | 630 |
597 chrome.fileBrowserPrivate.onFileChanged.addListener( | 631 chrome.fileBrowserPrivate.onFileChanged.addListener( |
598 this.onFileChanged_.bind(this)); | 632 this.onFileChanged_.bind(this)); |
599 | 633 |
600 var self = this; | 634 var self = this; |
601 | 635 |
602 // The list of callbacks to be invoked during the directory rescan after | 636 // The list of callbacks to be invoked during the directory rescan after |
603 // all paste tasks are complete. | 637 // all paste tasks are complete. |
604 this.pasteSuccessCallbacks_ = []; | 638 this.pasteSuccessCallbacks_ = []; |
605 | 639 |
606 this.initCommands_(); | |
607 | |
608 this.setupCurrentDirectory_(); | 640 this.setupCurrentDirectory_(); |
609 | 641 |
610 this.summarizeSelection_(); | 642 this.summarizeSelection_(); |
611 | 643 |
612 this.dataModel_.sort('cachedMtime_', 'desc'); | 644 this.dataModel_.sort('cachedMtime_', 'desc'); |
613 | 645 |
614 this.refocus(); | 646 this.refocus(); |
615 | 647 |
616 this.createMetadataProvider_(); | 648 this.createMetadataProvider_(); |
617 metrics.recordTime('Load.DOM'); | 649 metrics.recordTime('Load.DOM'); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
656 // Cache nodes we'll be manipulating. | 688 // Cache nodes we'll be manipulating. |
657 this.previewThumbnails_ = | 689 this.previewThumbnails_ = |
658 this.dialogDom_.querySelector('.preview-thumbnails'); | 690 this.dialogDom_.querySelector('.preview-thumbnails'); |
659 this.previewPanel_ = this.dialogDom_.querySelector('.preview-panel'); | 691 this.previewPanel_ = this.dialogDom_.querySelector('.preview-panel'); |
660 this.previewFilename_ = this.dialogDom_.querySelector('.preview-filename'); | 692 this.previewFilename_ = this.dialogDom_.querySelector('.preview-filename'); |
661 this.previewSummary_ = this.dialogDom_.querySelector('.preview-summary'); | 693 this.previewSummary_ = this.dialogDom_.querySelector('.preview-summary'); |
662 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); | 694 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); |
663 this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons'); | 695 this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons'); |
664 this.okButton_ = this.dialogDom_.querySelector('.ok'); | 696 this.okButton_ = this.dialogDom_.querySelector('.ok'); |
665 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); | 697 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); |
666 this.newFolderButton_ = this.dialogDom_.querySelector('.new-folder'); | |
667 this.deleteButton_ = this.dialogDom_.querySelector('.delete-button'); | 698 this.deleteButton_ = this.dialogDom_.querySelector('.delete-button'); |
668 | 699 |
669 this.downloadsWarning_ = | 700 this.downloadsWarning_ = |
670 this.dialogDom_.querySelector('.downloads-warning'); | 701 this.dialogDom_.querySelector('.downloads-warning'); |
671 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING')); | 702 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING')); |
672 this.downloadsWarning_.lastElementChild.innerHTML = html; | 703 this.downloadsWarning_.lastElementChild.innerHTML = html; |
673 var link = this.downloadsWarning_.querySelector('a'); | 704 var link = this.downloadsWarning_.querySelector('a'); |
674 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this)); | 705 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this)); |
675 | 706 |
676 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); | 707 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); |
(...skipping 10 matching lines...) Expand all Loading... | |
687 'keyup', this.onFilenameInputKeyUp_.bind(this)); | 718 'keyup', this.onFilenameInputKeyUp_.bind(this)); |
688 this.filenameInput_.addEventListener( | 719 this.filenameInput_.addEventListener( |
689 'focus', this.onFilenameInputFocus_.bind(this)); | 720 'focus', this.onFilenameInputFocus_.bind(this)); |
690 | 721 |
691 var listContainer = this.dialogDom_.querySelector('.list-container'); | 722 var listContainer = this.dialogDom_.querySelector('.list-container'); |
692 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this)); | 723 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this)); |
693 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this)); | 724 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this)); |
694 this.okButton_.addEventListener('click', this.onOk_.bind(this)); | 725 this.okButton_.addEventListener('click', this.onOk_.bind(this)); |
695 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); | 726 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); |
696 | 727 |
697 this.dialogDom_.querySelector('button.new-folder').addEventListener( | 728 this.dialogDom_.querySelector('div.open-sidebar').addEventListener( |
698 'click', this.onNewFolderButtonClick_.bind(this)); | 729 'click', this.onToggleSidebar_.bind(this)); |
730 this.dialogDom_.querySelector('div.close-sidebar').addEventListener( | |
731 'click', this.onToggleSidebar_.bind(this)); | |
732 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); | |
699 | 733 |
700 this.dialogDom_.querySelector('button.detail-view').addEventListener( | 734 this.dialogDom_.querySelector('button.detail-view').addEventListener( |
701 'click', this.onDetailViewButtonClick_.bind(this)); | 735 'click', this.onDetailViewButtonClick_.bind(this)); |
702 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener( | 736 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener( |
703 'click', this.onThumbnailViewButtonClick_.bind(this)); | 737 'click', this.onThumbnailViewButtonClick_.bind(this)); |
704 | 738 |
705 this.dialogDom_.ownerDocument.defaultView.addEventListener( | 739 this.dialogDom_.ownerDocument.defaultView.addEventListener( |
706 'resize', this.onResize_.bind(this)); | 740 'resize', this.onResize_.bind(this)); |
707 | 741 |
708 var ary = this.dialogDom_.querySelectorAll('[visibleif]'); | 742 var ary = this.dialogDom_.querySelectorAll('[visibleif]'); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
741 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || | 775 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || |
742 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FOLDER || | 776 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FOLDER || |
743 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { | 777 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { |
744 this.selectionModelClass_ = cr.ui.ListSingleSelectionModel; | 778 this.selectionModelClass_ = cr.ui.ListSingleSelectionModel; |
745 } else { | 779 } else { |
746 this.selectionModelClass_ = cr.ui.ListSelectionModel; | 780 this.selectionModelClass_ = cr.ui.ListSelectionModel; |
747 } | 781 } |
748 | 782 |
749 this.initTable_(); | 783 this.initTable_(); |
750 this.initGrid_(); | 784 this.initGrid_(); |
785 this.initRootsList_(); | |
751 | 786 |
752 this.setListType(FileManager.ListType.DETAIL); | 787 this.setListType(FileManager.ListType.DETAIL); |
753 | 788 |
754 this.onResize_(); | 789 this.onResize_(); |
755 | 790 |
756 this.textSearchState_ = {text: '', date: new Date()}; | 791 this.textSearchState_ = {text: '', date: new Date()}; |
757 }; | 792 }; |
758 | 793 |
794 FileManager.prototype.initRootsList_ = function() { | |
795 this.rootsList_ = this.dialogDom_.querySelector('.roots-list'); | |
796 cr.ui.List.decorate(this.rootsList_); | |
797 | |
798 var self = this; | |
799 this.rootsList_.itemConstructor = function(entry) { | |
800 return self.renderRoot_(entry); | |
801 }; | |
802 | |
803 this.rootsList_.selectionModel = new cr.ui.ListSingleSelectionModel(); | |
804 this.rootsList_.selectionModel.addEventListener( | |
805 'change', this.onRootsSelectionChanged_.bind(this)); | |
806 | |
807 // TODO(dgozman): add "Add a drive" item. | |
808 this.rootsList_.dataModel = new cr.ui.ArrayDataModel(this.rootEntries_); | |
809 }; | |
810 | |
811 FileManager.prototype.updateRoots_ = function(opt_changeDirectoryTo) { | |
812 var self = this; | |
813 this.resolveRoots_(function(rootEntries) { | |
814 self.rootEntries_ = rootEntries; | |
815 | |
816 var dataModel = self.rootsList_.dataModel; | |
817 var args = [0, dataModel.length].concat(rootEntries); | |
818 dataModel.splice.apply(dataModel, args); | |
819 | |
820 self.updateRootsListSelection_(); | |
821 | |
822 if (opt_changeDirectoryTo) | |
823 self.changeDirectory(opt_changeDirectoryTo); | |
824 }); | |
825 }; | |
826 | |
759 /** | 827 /** |
760 * Get the icon type for a given Entry. | 828 * Get the icon type for a given Entry. |
761 * | 829 * |
762 * @param {Entry} entry An Entry subclass (FileEntry or DirectoryEntry). | 830 * @param {Entry} entry An Entry subclass (FileEntry or DirectoryEntry). |
763 * @return {string} | 831 * @return {string} |
764 */ | 832 */ |
765 FileManager.prototype.getIconType = function(entry) { | 833 FileManager.prototype.getIconType = function(entry) { |
766 if (!('cachedIconType_' in entry)) | 834 if (!('cachedIconType_' in entry)) |
767 entry.cachedIconType_ = this.computeIconType_(entry); | 835 entry.cachedIconType_ = this.computeIconType_(entry); |
768 return entry.cachedIconType_; | 836 return entry.cachedIconType_; |
769 }; | 837 }; |
770 | 838 |
771 /** | 839 /** |
772 * Extract extension from the file name and cat it to to lower case. | 840 * Extract extension from the file name and cat it to to lower case. |
773 * | 841 * |
774 * @param {string} name. | 842 * @param {string} name. |
775 * @return {strin} | 843 * @return {strin} |
776 */ | 844 */ |
777 function getFileExtension(name) { | 845 function getFileExtension(name) { |
778 var extIndex = name.lastIndexOf('.'); | 846 var extIndex = name.lastIndexOf('.'); |
779 if (extIndex < 0) | 847 if (extIndex < 0) |
780 return ''; | 848 return ''; |
781 | 849 |
782 return name.substr(extIndex + 1).toLowerCase(); | 850 return name.substr(extIndex + 1).toLowerCase(); |
783 } | 851 } |
784 | 852 |
785 FileManager.prototype.computeIconType_ = function(entry) { | 853 FileManager.prototype.computeIconType_ = function(entry) { |
854 // TODO(dgozman): refactor this to use proper icons in left panel, | |
855 // and do not depend on mountPoints. | |
786 var deviceNumber = this.getDeviceNumber(entry); | 856 var deviceNumber = this.getDeviceNumber(entry); |
787 if (deviceNumber != undefined) { | 857 if (deviceNumber != undefined) { |
788 if (this.mountPoints_[deviceNumber].mountCondition == '') | 858 if (this.mountPoints_[deviceNumber].mountCondition == '') |
789 return 'device'; | 859 return 'device'; |
790 var mountCondition = this.mountPoints_[deviceNumber].mountCondition; | 860 var mountCondition = this.mountPoints_[deviceNumber].mountCondition; |
791 if (mountCondition == 'unknown_filesystem' || | 861 if (mountCondition == 'unknown_filesystem' || |
792 mountCondition == 'unsupported_filesystem') | 862 mountCondition == 'unsupported_filesystem') |
793 return 'unreadable'; | 863 return 'unreadable'; |
794 } | 864 } |
795 if (entry.isDirectory) | 865 if (entry.isDirectory) |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1068 !isSystemDirEntry(this.currentDirEntry_)); | 1138 !isSystemDirEntry(this.currentDirEntry_)); |
1069 | 1139 |
1070 case 'delete': | 1140 case 'delete': |
1071 return (// Initialized to the point where we have a current directory | 1141 return (// Initialized to the point where we have a current directory |
1072 this.currentDirEntry_ && | 1142 this.currentDirEntry_ && |
1073 // Rename not in progress. | 1143 // Rename not in progress. |
1074 !this.renameInput_.currentEntry && | 1144 !this.renameInput_.currentEntry && |
1075 !isSystemDirEntry(this.currentDirEntry_)) && | 1145 !isSystemDirEntry(this.currentDirEntry_)) && |
1076 this.selection && | 1146 this.selection && |
1077 this.selection.totalCount > 0; | 1147 this.selection.totalCount > 0; |
1148 | |
1149 case 'newfolder': | |
1150 return this.currentDirEntry_ && | |
1151 (this.dialogType_ == 'saveas-file' || | |
1152 this.dialogType_ == 'full-page'); | |
1078 } | 1153 } |
1079 }; | 1154 }; |
1080 | 1155 |
1081 FileManager.prototype.updateCommonActionButtons_ = function() { | 1156 FileManager.prototype.updateCommonActionButtons_ = function() { |
1082 if (this.deleteButton_) | 1157 if (this.deleteButton_) |
1083 this.deleteButton_.disabled = !this.canExecute_('delete'); | 1158 this.deleteButton_.disabled = !this.canExecute_('delete'); |
1084 }; | 1159 }; |
1085 | 1160 |
1086 FileManager.prototype.setListType = function(type) { | 1161 FileManager.prototype.setListType = function(type) { |
1087 if (type && type == this.listType_) | 1162 if (type && type == this.listType_) |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1275 leadIndex); | 1350 leadIndex); |
1276 return; | 1351 return; |
1277 } | 1352 } |
1278 | 1353 |
1279 this.initiateRename_(label); | 1354 this.initiateRename_(label); |
1280 return; | 1355 return; |
1281 | 1356 |
1282 case 'delete': | 1357 case 'delete': |
1283 this.deleteEntries(this.selection.entries); | 1358 this.deleteEntries(this.selection.entries); |
1284 return; | 1359 return; |
1360 | |
1361 case 'newfolder': | |
1362 this.onNewFolderCommand_(event); | |
1363 return; | |
1285 } | 1364 } |
1286 }; | 1365 }; |
1287 | 1366 |
1288 /** | 1367 /** |
1289 * Respond to the back and forward buttons. | 1368 * Respond to the back and forward buttons. |
1290 */ | 1369 */ |
1291 FileManager.prototype.onPopState_ = function(event) { | 1370 FileManager.prototype.onPopState_ = function(event) { |
1292 // TODO(serya): We should restore selected items here. | 1371 // TODO(serya): We should restore selected items here. |
1293 if (this.rootEntries_) | 1372 if (this.rootEntries_) |
1294 this.setupCurrentDirectory_(); | 1373 this.setupCurrentDirectory_(); |
1295 }; | 1374 }; |
1296 | 1375 |
1297 FileManager.prototype.requestResize_ = function(timeout) { | 1376 FileManager.prototype.requestResize_ = function(timeout) { |
1298 var self = this; | 1377 var self = this; |
1299 setTimeout(function() { self.onResize_() }, timeout || 0); | 1378 setTimeout(function() { self.onResize_() }, timeout || 0); |
1300 }; | 1379 }; |
1301 | 1380 |
1302 /** | 1381 /** |
1303 * Resize details and thumb views to fit the new window size. | 1382 * Resize details and thumb views to fit the new window size. |
1304 */ | 1383 */ |
1305 FileManager.prototype.onResize_ = function() { | 1384 FileManager.prototype.onResize_ = function() { |
1306 this.table_.style.height = this.grid_.style.height = | 1385 this.table_.style.height = this.grid_.style.height = |
1307 this.grid_.parentNode.clientHeight + 'px'; | 1386 this.grid_.parentNode.clientHeight + 'px'; |
1308 this.table_.style.width = this.grid_.style.width = | |
1309 this.grid_.parentNode.clientWidth + 'px'; | |
1310 | |
1311 this.table_.list_.style.width = this.table_.parentNode.clientWidth + 'px'; | |
1312 this.table_.list_.style.height = (this.table_.clientHeight - 1 - | 1387 this.table_.list_.style.height = (this.table_.clientHeight - 1 - |
1313 this.table_.header_.clientHeight) + 'px'; | 1388 this.table_.header_.clientHeight) + 'px'; |
1314 | 1389 |
1315 if (this.listType_ == FileManager.ListType.THUMBNAIL) { | 1390 if (this.listType_ == FileManager.ListType.THUMBNAIL) { |
1316 var self = this; | 1391 var self = this; |
1317 setTimeout(function() { | 1392 setTimeout(function() { |
1318 self.grid_.columns = 0; | 1393 self.grid_.columns = 0; |
1319 self.grid_.redraw(); | 1394 self.grid_.redraw(); |
1320 }, 0); | 1395 }, 0); |
1321 } else { | 1396 } else { |
1322 this.currentList_.redraw(); | 1397 this.currentList_.redraw(); |
1323 } | 1398 } |
1399 | |
1400 this.rootsList_.style.height = | |
1401 this.rootsList_.parentNode.clientHeight + 'px'; | |
1402 this.rootsList_.redraw(); | |
1324 }; | 1403 }; |
1325 | 1404 |
1326 FileManager.prototype.resolvePath = function( | 1405 FileManager.prototype.resolvePath = function( |
1327 path, resultCallback, errorCallback) { | 1406 path, resultCallback, errorCallback) { |
1328 return util.resolvePath(this.filesystem_.root, path, resultCallback, | 1407 return util.resolvePath(this.filesystem_.root, path, resultCallback, |
1329 errorCallback); | 1408 errorCallback); |
1330 }; | 1409 }; |
1331 | 1410 |
1332 /** | 1411 /** |
1333 * Restores current directory and may be a selected item after page load (or | 1412 * Restores current directory and may be a selected item after page load (or |
(...skipping 13 matching lines...) Expand all Loading... | |
1347 this.setupPath_(this.params_.defaultPath); | 1426 this.setupPath_(this.params_.defaultPath); |
1348 } else { | 1427 } else { |
1349 this.setupDefaultPath_(); | 1428 this.setupDefaultPath_(); |
1350 } | 1429 } |
1351 }; | 1430 }; |
1352 | 1431 |
1353 FileManager.prototype.setupDefaultPath_ = function() { | 1432 FileManager.prototype.setupDefaultPath_ = function() { |
1354 // No preset given, find a good place to start. | 1433 // No preset given, find a good place to start. |
1355 // Check for removable devices, if there are none, go to Downloads. | 1434 // Check for removable devices, if there are none, go to Downloads. |
1356 var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) { | 1435 var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) { |
1357 return rootEntry.fullPath == REMOVABLE_DIRECTORY; | 1436 return isParentPath(REMOVABLE_DIRECTORY, rootEntry.fullPath); |
1358 })[0]; | 1437 })[0]; |
1359 if (!removableDirectoryEntry) { | 1438 var path = (removableDirectoryEntry && removableDirectoryEntry.fullPath) || |
arv (Not doing code reviews)
2011/11/30 18:21:12
too many parentheses
dgozman
2011/12/01 10:13:04
Done.
| |
1360 this.changeDirectory(DOWNLOADS_DIRECTORY, CD_NO_HISTORY); | 1439 DOWNLOADS_DIRECTORY; |
1361 return; | 1440 this.changeDirectory(path, CD_NO_HISTORY); |
1362 } | |
1363 | |
1364 var foundRemovable = false; | |
1365 util.forEachDirEntry(removableDirectoryEntry, function(result) { | |
1366 if (result) { | |
1367 foundRemovable = true; | |
1368 } else { // Done enumerating, and we know the answer. | |
1369 this.changeDirectory(foundRemovable ? '/' : DOWNLOADS_DIRECTORY, | |
1370 CD_NO_HISTORY); | |
1371 } | |
1372 }.bind(this)); | |
1373 }; | 1441 }; |
1374 | 1442 |
1375 FileManager.prototype.setupPath_ = function(path) { | 1443 FileManager.prototype.setupPath_ = function(path) { |
1376 // Split the dirname from the basename. | 1444 // Split the dirname from the basename. |
1377 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); | 1445 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); |
1378 if (!ary) { | 1446 if (!ary) { |
1379 console.warn('Unable to split default path: ' + path); | 1447 console.warn('Unable to split default path: ' + path); |
1380 self.changeDirectory('/', CD_NO_HISTORY); | 1448 self.changeDirectory('/', CD_NO_HISTORY); |
1381 return; | 1449 return; |
1382 } | 1450 } |
(...skipping 16 matching lines...) Expand all Loading... | |
1399 return; | 1467 return; |
1400 } | 1468 } |
1401 | 1469 |
1402 // Leaf is an existing file, cd to its parent directory and select it. | 1470 // Leaf is an existing file, cd to its parent directory and select it. |
1403 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY, leafEntry.name); | 1471 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY, leafEntry.name); |
1404 } | 1472 } |
1405 | 1473 |
1406 function onLeafError(err) { | 1474 function onLeafError(err) { |
1407 // Set filename first so OK button will update in changeDirectoryEntry. | 1475 // Set filename first so OK button will update in changeDirectoryEntry. |
1408 self.filenameInput_.value = leafName; | 1476 self.filenameInput_.value = leafName; |
1477 self.selectDefaultPathInFilenameInput_(); | |
1409 if (err = FileError.NOT_FOUND_ERR) { | 1478 if (err = FileError.NOT_FOUND_ERR) { |
1410 // Leaf does not exist, it's just a suggested file name. | 1479 // Leaf does not exist, it's just a suggested file name. |
1411 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY); | 1480 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY); |
1412 } else { | 1481 } else { |
1413 console.log('Unexpected error resolving default leaf: ' + err); | 1482 console.log('Unexpected error resolving default leaf: ' + err); |
1414 self.changeDirectoryEntry('/', CD_NO_HISTORY); | 1483 self.changeDirectoryEntry('/', CD_NO_HISTORY); |
1415 } | 1484 } |
1416 } | 1485 } |
1417 | 1486 |
1418 self.resolvePath(path, onLeafFound, onLeafError); | 1487 self.resolvePath(path, onLeafFound, onLeafError); |
1419 } | 1488 } |
1420 | 1489 |
1421 function onBaseError(err) { | 1490 function onBaseError(err) { |
1422 // Set filename first so OK button will update in changeDirectory. | 1491 // Set filename first so OK button will update in changeDirectory. |
1423 self.filenameInput_.value = leafName; | 1492 self.filenameInput_.value = leafName; |
1493 self.selectDefaultPathInFilenameInput_(); | |
1424 console.log('Unexpected error resolving default base "' + | 1494 console.log('Unexpected error resolving default base "' + |
1425 baseName + '": ' + err); | 1495 baseName + '": ' + err); |
1426 self.changeDirectory('/', CD_NO_HISTORY); | 1496 self.changeDirectory('/', CD_NO_HISTORY); |
1427 } | 1497 } |
1428 | 1498 |
1429 if (baseName) { | 1499 if (baseName) { |
1430 this.filesystem_.root.getDirectory( | 1500 this.filesystem_.root.getDirectory( |
1431 baseName, {create: false}, onBaseFound, onBaseError); | 1501 baseName, {create: false}, onBaseFound, onBaseError); |
1432 } else { | 1502 } else { |
1433 onBaseFound(this.filesystem_.root); | 1503 onBaseFound(this.filesystem_.root); |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1652 li.className = 'thumbnail-item'; | 1722 li.className = 'thumbnail-item'; |
1653 | 1723 |
1654 if (this.showCheckboxes_) | 1724 if (this.showCheckboxes_) |
1655 li.appendChild(this.renderCheckbox_(entry)); | 1725 li.appendChild(this.renderCheckbox_(entry)); |
1656 | 1726 |
1657 li.appendChild(this.renderThumbnailBox_(entry, false)); | 1727 li.appendChild(this.renderThumbnailBox_(entry, false)); |
1658 | 1728 |
1659 var div = this.document_.createElement('div'); | 1729 var div = this.document_.createElement('div'); |
1660 div.className = 'filename-label'; | 1730 div.className = 'filename-label'; |
1661 var labelText = entry.name; | 1731 var labelText = entry.name; |
1662 if (this.currentDirEntry_.name == '') | |
1663 labelText = this.getLabelForRootPath_(labelText); | |
1664 | 1732 |
1665 div.textContent = labelText; | 1733 div.textContent = labelText; |
1666 div.entry = entry; | 1734 div.entry = entry; |
1667 | 1735 |
1668 li.appendChild(div); | 1736 li.appendChild(div); |
1669 | 1737 |
1670 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); | 1738 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); |
1671 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); | 1739 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); |
1672 return li; | 1740 return li; |
1673 }; | 1741 }; |
(...skipping 13 matching lines...) Expand all Loading... | |
1687 | 1755 |
1688 var icon = this.document_.createElement('div'); | 1756 var icon = this.document_.createElement('div'); |
1689 icon.className = 'detail-icon'; | 1757 icon.className = 'detail-icon'; |
1690 this.getIconType(entry); | 1758 this.getIconType(entry); |
1691 icon.setAttribute('iconType', entry.cachedIconType_); | 1759 icon.setAttribute('iconType', entry.cachedIconType_); |
1692 div.appendChild(icon); | 1760 div.appendChild(icon); |
1693 | 1761 |
1694 return div; | 1762 return div; |
1695 }; | 1763 }; |
1696 | 1764 |
1697 FileManager.prototype.getLabelForRootPath_ = function(path) { | 1765 /** |
1698 // This hack lets us localize the top level directories. | 1766 * Return the localized name for the root. |
1699 if (path == 'Downloads') | 1767 * @param {string} path The full path of the root (starting with slash). |
1700 return str('DOWNLOADS_DIRECTORY_LABEL'); | 1768 * @return {string} The localized name. |
1769 */ | |
1770 FileManager.prototype.getRootLabel_ = function(path) { | |
1771 if (path == DOWNLOADS_DIRECTORY) | |
1772 return str('CHROMEBOOK_DIRECTORY_LABEL'); | |
1701 | 1773 |
1702 if (path == 'archive') | 1774 if (path == ARCHIVE_DIRECTORY) |
1703 return str('ARCHIVE_DIRECTORY_LABEL'); | 1775 return str('ARCHIVE_DIRECTORY_LABEL'); |
1776 if (isParentPath(ARCHIVE_DIRECTORY, path)) | |
1777 return path.substring(ARCHIVE_DIRECTORY.length + 1); | |
1704 | 1778 |
1705 if (path == 'removable') | 1779 if (path == REMOVABLE_DIRECTORY) |
1706 return str('REMOVABLE_DIRECTORY_LABEL'); | 1780 return str('REMOVABLE_DIRECTORY_LABEL'); |
1781 if (isParentPath(REMOVABLE_DIRECTORY, path)) | |
1782 return path.substring(REMOVABLE_DIRECTORY.length + 1); | |
1707 | 1783 |
1708 return path || str('ROOT_DIRECTORY_LABEL'); | 1784 return path; |
1785 }; | |
1786 | |
1787 FileManager.prototype.getRootIconUrl_ = function(path, opt_small) { | |
1788 var iconUrl = opt_small ? 'images/chromebook_28x28.png' : | |
1789 'images/chromebook_24x24.png'; | |
1790 if (isParentPath(REMOVABLE_DIRECTORY, path)) | |
1791 iconUrl = 'images/filetype_device.png'; | |
1792 if (isParentPath(ARCHIVE_DIRECTORY, path)) | |
arv (Not doing code reviews)
2011/11/30 18:21:12
else if?
dgozman
2011/12/01 10:13:04
Done.
| |
1793 iconUrl = 'images/icon_mount_archive_16x16.png'; | |
1794 return chrome.extension.getURL(iconUrl); | |
1795 }; | |
1796 | |
1797 FileManager.prototype.renderRoot_ = function(entry) { | |
1798 var li = this.document_.createElement('li'); | |
1799 li.className = 'root-item'; | |
1800 | |
1801 var icon = this.document_.createElement('img'); | |
1802 icon.setAttribute('src', this.getRootIconUrl_(entry.fullPath, false)); | |
arv (Not doing code reviews)
2011/11/30 18:21:12
icon.src = ...
dgozman
2011/12/01 10:13:04
Done.
| |
1803 li.appendChild(icon); | |
1804 | |
1805 var div = this.document_.createElement('div'); | |
1806 div.textContent = this.getRootLabel_(entry.fullPath); | |
1807 li.appendChild(div); | |
1808 | |
1809 if (isParentPath(REMOVABLE_DIRECTORY, entry.fullPath) || | |
1810 isParentPath(ARCHIVE_DIRECTORY, entry.fullPath)) { | |
1811 var spacer = this.document_.createElement('div'); | |
1812 spacer.className = 'spacer'; | |
1813 li.appendChild(spacer); | |
1814 | |
1815 var eject = this.document_.createElement('img'); | |
1816 eject.className = 'root-eject'; | |
1817 eject.setAttribute('src', chrome.extension.getURL('images/eject.png')); | |
1818 eject.addEventListener('click', this.onEjectClick_.bind(this, entry)); | |
1819 li.appendChild(eject); | |
1820 } | |
1821 | |
1822 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); | |
1823 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); | |
1824 return li; | |
1825 }; | |
1826 | |
1827 /** | |
1828 * Handler for eject button clicked. | |
1829 * @param {Entry} entry Entry to eject. | |
1830 * @param {Event} event The event. | |
1831 */ | |
1832 FileManager.prototype.onEjectClick_ = function(entry, event) { | |
1833 this.unmountRequests_.push(entry.toURL()); | |
1834 chrome.fileBrowserPrivate.removeMount(entry.fullPath); | |
1709 }; | 1835 }; |
1710 | 1836 |
1711 /** | 1837 /** |
1712 * Render the Name column of the detail table. | 1838 * Render the Name column of the detail table. |
1713 * | 1839 * |
1714 * Invoked by cr.ui.Table when a file needs to be rendered. | 1840 * Invoked by cr.ui.Table when a file needs to be rendered. |
1715 * | 1841 * |
1716 * @param {Entry} entry The Entry object to render. | 1842 * @param {Entry} entry The Entry object to render. |
1717 * @param {string} columnId The id of the column to be rendered. | 1843 * @param {string} columnId The id of the column to be rendered. |
1718 * @param {cr.ui.Table} table The table doing the rendering. | 1844 * @param {cr.ui.Table} table The table doing the rendering. |
1719 */ | 1845 */ |
1720 FileManager.prototype.renderName_ = function(entry, columnId, table) { | 1846 FileManager.prototype.renderName_ = function(entry, columnId, table) { |
1721 var label = this.document_.createElement('div'); | 1847 var label = this.document_.createElement('div'); |
1722 label.appendChild(this.renderIconType_(entry, columnId, table)); | 1848 label.appendChild(this.renderIconType_(entry, columnId, table)); |
1723 label.entry = entry; | 1849 label.entry = entry; |
1724 label.className = 'detail-name filename-label'; | 1850 label.className = 'detail-name filename-label'; |
1725 if (this.currentDirEntry_.name == '') { | 1851 label.appendChild(this.document_.createTextNode(entry.name)); |
1726 label.appendChild(this.document_.createTextNode( | |
1727 this.getLabelForRootPath_(entry.name))); | |
1728 } else { | |
1729 label.appendChild(this.document_.createTextNode(entry.name)); | |
1730 } | |
1731 | |
1732 return label; | 1852 return label; |
1733 }; | 1853 }; |
1734 | 1854 |
1735 /** | 1855 /** |
1736 * Render the Size column of the detail table. | 1856 * Render the Size column of the detail table. |
1737 * | 1857 * |
1738 * @param {Entry} entry The Entry object to render. | 1858 * @param {Entry} entry The Entry object to render. |
1739 * @param {string} columnId The id of the column to be rendered. | 1859 * @param {string} columnId The id of the column to be rendered. |
1740 * @param {cr.ui.Table} table The table doing the rendering. | 1860 * @param {cr.ui.Table} table The table doing the rendering. |
1741 */ | 1861 */ |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2107 // Skip the button creation. | 2227 // Skip the button creation. |
2108 if (!str('ENABLE_PHOTO_EDITOR')) continue; | 2228 if (!str('ENABLE_PHOTO_EDITOR')) continue; |
2109 this.galleryTask_ = task; | 2229 this.galleryTask_ = task; |
2110 } | 2230 } |
2111 } | 2231 } |
2112 this.renderTaskButton_(task); | 2232 this.renderTaskButton_(task); |
2113 } | 2233 } |
2114 | 2234 |
2115 // These are done in separate functions, as the checks require | 2235 // These are done in separate functions, as the checks require |
2116 // asynchronous function calls. | 2236 // asynchronous function calls. |
2117 this.maybeRenderUnmountTask_(selection); | |
2118 this.maybeRenderFormattingTask_(selection); | 2237 this.maybeRenderFormattingTask_(selection); |
2119 }; | 2238 }; |
2120 | 2239 |
2121 FileManager.prototype.renderTaskButton_ = function(task) { | 2240 FileManager.prototype.renderTaskButton_ = function(task) { |
2122 var button = this.document_.createElement('button'); | 2241 var button = this.document_.createElement('button'); |
2123 button.addEventListener('click', | 2242 button.addEventListener('click', |
2124 this.onTaskButtonClicked_.bind(this, task)); | 2243 this.onTaskButtonClicked_.bind(this, task)); |
2125 button.className = 'task-button'; | 2244 button.className = 'task-button'; |
2126 | 2245 |
2127 var img = this.document_.createElement('img'); | 2246 var img = this.document_.createElement('img'); |
2128 img.src = task.iconUrl; | 2247 img.src = task.iconUrl; |
2129 | 2248 |
2130 button.appendChild(img); | 2249 button.appendChild(img); |
2131 var label = this.document_.createElement('div'); | 2250 var label = this.document_.createElement('div'); |
2132 label.appendChild(this.document_.createTextNode(task.title)) | 2251 label.appendChild(this.document_.createTextNode(task.title)) |
2133 button.appendChild(label); | 2252 button.appendChild(label); |
2134 | 2253 |
2135 this.taskButtons_.appendChild(button); | 2254 this.taskButtons_.appendChild(button); |
2136 }; | 2255 }; |
2137 | 2256 |
2138 /** | 2257 /** |
2139 * Checks whether unmount task should be displayed and if the answer is | |
2140 * affirmative renders it. | |
2141 * @param {Object} selection Selected files object. | |
2142 */ | |
2143 FileManager.prototype.maybeRenderUnmountTask_ = function(selection) { | |
2144 for (var index = 0; index < selection.urls.length; ++index) { | |
2145 // Each url should be a mount point. | |
2146 var path = selection.entries[index].fullPath; | |
2147 var found = false; | |
2148 for (var i = 0; i < this.mountPoints_.length; i++) { | |
2149 var mountPath = this.mountPoints_[i].mountPath; | |
2150 if (mountPath[0] != '/') { | |
2151 mountPath = '/' + mountPath; | |
2152 } | |
2153 if (mountPath == path && this.mountPoints_[i].mountType == 'file') { | |
2154 found = true; | |
2155 break; | |
2156 } | |
2157 } | |
2158 if (!found) | |
2159 return; | |
2160 } | |
2161 this.renderTaskButton_({ | |
2162 taskId: this.getExtensionId_() + '|unmount-archive', | |
2163 iconUrl: | |
2164 chrome.extension.getURL('images/icon_unmount_archive_16x16.png'), | |
2165 title: str('UNMOUNT_ARCHIVE'), | |
2166 internal: true | |
2167 }); | |
2168 }; | |
2169 | |
2170 /** | |
2171 * Checks whether formatting task should be displayed and if the answer is | 2258 * Checks whether formatting task should be displayed and if the answer is |
2172 * affirmative renders it. Includes asynchronous calls, so it's splitted into | 2259 * affirmative renders it. Includes asynchronous calls, so it's splitted into |
2173 * three parts. | 2260 * three parts. |
2174 * @param {Object} selection Selected files object. | 2261 * @param {Object} selection Selected files object. |
2175 */ | 2262 */ |
2176 FileManager.prototype.maybeRenderFormattingTask_ = function(selection) { | 2263 FileManager.prototype.maybeRenderFormattingTask_ = function(selection) { |
2177 // Not to make unnecessary getMountPoints() call we doublecheck if there is | 2264 // Not to make unnecessary getMountPoints() call we doublecheck if there is |
2178 // only one selected entry. | 2265 // only one selected entry. |
2179 if (selection.entries.length != 1) | 2266 if (selection.entries.length != 1) |
2180 return; | 2267 return; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2241 chrome.fileBrowserPrivate.executeTask(task.taskId, urls); | 2328 chrome.fileBrowserPrivate.executeTask(task.taskId, urls); |
2242 }; | 2329 }; |
2243 | 2330 |
2244 /** | 2331 /** |
2245 * Event handler called when some volume was mounted or unmouted. | 2332 * Event handler called when some volume was mounted or unmouted. |
2246 */ | 2333 */ |
2247 FileManager.prototype.onMountCompleted_ = function(event) { | 2334 FileManager.prototype.onMountCompleted_ = function(event) { |
2248 var self = this; | 2335 var self = this; |
2249 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { | 2336 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { |
2250 self.mountPoints_ = mountPoints; | 2337 self.mountPoints_ = mountPoints; |
2338 var changeDirectoryTo = null; | |
2339 | |
2251 if (event.eventType == 'mount') { | 2340 if (event.eventType == 'mount') { |
2252 for (var index = 0; index < self.mountRequests_.length; ++index) { | 2341 // Mount request finished - remove it. |
2253 if (self.mountRequests_[index] == event.sourceUrl) { | 2342 var index = self.mountRequests_.indexOf(event.sourceUrl); |
2254 self.mountRequests_.splice(index, 1); | 2343 if (index != -1) { |
2255 if (event.status == 'success') { | 2344 self.mountRequests_.splice(index, 1); |
2256 self.changeDirectory(event.mountPath); | 2345 // Go to mounted directory, if request was initiated from this tab. |
2257 } else { | 2346 if (event.status == 'success') |
2258 // Report mount error. | 2347 changeDirectoryTo = event.mountPath; |
2259 if (event.mountType == 'file') { | |
2260 var fileName = event.sourceUrl.substr( | |
2261 event.sourceUrl.lastIndexOf('/') + 1); | |
2262 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName, | |
2263 event.status)); | |
2264 } | |
2265 } | |
2266 return; | |
2267 } | |
2268 } | 2348 } |
2269 } | 2349 } |
2270 | 2350 |
2351 if (event.eventType == 'unmount') { | |
2352 // Unmount request finished - remove it. | |
2353 var index = self.unmountRequests_.indexOf(event.sourceUrl); | |
2354 if (index != -1) | |
2355 self.unmountRequests_.splice(index, 1); | |
2356 } | |
2357 | |
2358 if (event.eventType == 'mount' && event.status != 'success' && | |
2359 event.mountType == 'file') { | |
2360 // Report mount error. | |
2361 var fileName = event.sourceUrl.substr( | |
2362 event.sourceUrl.lastIndexOf('/') + 1); | |
2363 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName, | |
2364 event.status)); | |
2365 } | |
2366 | |
2367 if (event.eventType == 'unmount' && event.status != 'success') { | |
2368 // Report unmount error. | |
2369 // TODO(dgozman): introduce string and show alert here. | |
2370 } | |
2371 | |
2271 if (event.eventType == 'unmount' && event.status == 'success' && | 2372 if (event.eventType == 'unmount' && event.status == 'success' && |
2272 self.currentDirEntry_ && | 2373 self.currentDirEntry_ && |
2273 isParentPath(event.mountPath, self.currentDirEntry_.fullPath)) { | 2374 isParentPath(event.mountPath, self.currentDirEntry_.fullPath)) { |
2274 self.changeDirectory(getParentPath(event.mountPath)); | 2375 changeDirectoryTo = getParentPath(event.mountPath); |
2275 return; | |
2276 } | 2376 } |
2277 | 2377 |
2278 var rescanDirectoryNeeded = (event.status == 'success'); | 2378 // In the case of success, roots are changed and should be rescanned. |
2279 for (var i = 0; i < mountPoints.length; i++) { | 2379 if (event.status == 'success') |
2280 if (event.sourceUrl == mountPoints[i].sourceUrl && | 2380 self.updateRoots_(changeDirectoryTo); |
2281 mountPoints[i].mountCondition != '') { | |
2282 rescanDirectoryNeeded = true; | |
2283 } | |
2284 } | |
2285 // TODO(dgozman): rescan directory, only if it contains mounted points, | |
2286 // when mounts location will be decided. | |
2287 if (rescanDirectoryNeeded) | |
2288 self.rescanDirectory_(null, 300); | |
2289 }); | 2381 }); |
2290 }; | 2382 }; |
2291 | 2383 |
2292 /** | 2384 /** |
2293 * Event handler called when some internal task should be executed. | 2385 * Event handler called when some internal task should be executed. |
2294 */ | 2386 */ |
2295 FileManager.prototype.onFileTaskExecute_ = function(id, details) { | 2387 FileManager.prototype.onFileTaskExecute_ = function(id, details) { |
2296 var urls = details.urls; | 2388 var urls = details.urls; |
2297 if (id == 'preview') { | 2389 if (id == 'preview') { |
2298 g_slideshow_data = urls; | 2390 g_slideshow_data = urls; |
2299 chrome.tabs.create({url: "slideshow.html"}); | 2391 chrome.tabs.create({url: "slideshow.html"}); |
2300 } else if (id == 'play' || id == 'enqueue') { | 2392 } else if (id == 'play' || id == 'enqueue') { |
2301 chrome.fileBrowserPrivate.viewFiles(urls, id); | 2393 chrome.fileBrowserPrivate.viewFiles(urls, id); |
2302 } else if (id == 'mount-archive') { | 2394 } else if (id == 'mount-archive') { |
2303 for (var index = 0; index < urls.length; ++index) { | 2395 for (var index = 0; index < urls.length; ++index) { |
2304 this.mountRequests_.push(urls[index]); | 2396 this.mountRequests_.push(urls[index]); |
2305 chrome.fileBrowserPrivate.addMount(urls[index], 'file', {}); | 2397 chrome.fileBrowserPrivate.addMount(urls[index], 'file', {}); |
2306 } | 2398 } |
2307 } else if (id == 'unmount-archive') { | |
2308 for (var index = 0; index < urls.length; ++index) { | |
2309 chrome.fileBrowserPrivate.removeMount(urls[index]); | |
2310 } | |
2311 } else if (id == 'format-device') { | 2399 } else if (id == 'format-device') { |
2312 this.confirm.show(str('FORMATTING_WARNING'), function() { | 2400 this.confirm.show(str('FORMATTING_WARNING'), function() { |
2313 chrome.fileBrowserPrivate.formatDevice(urls[0]); | 2401 chrome.fileBrowserPrivate.formatDevice(urls[0]); |
2314 }); | 2402 }); |
2315 } else if (id == 'gallery') { | 2403 } else if (id == 'gallery') { |
2316 // Pass to gallery all possible tasks except the gallery itself. | 2404 // Pass to gallery all possible tasks except the gallery itself. |
2317 var noGallery = []; | 2405 var noGallery = []; |
2318 for (var index = 0; index < details.task.allTasks.length; index++) { | 2406 for (var index = 0; index < details.task.allTasks.length; index++) { |
2319 var task = details.task.allTasks[index]; | 2407 var task = details.task.allTasks[index]; |
2320 if (task.taskId != this.getExtensionId_() + '|gallery') { | 2408 if (task.taskId != this.getExtensionId_() + '|gallery') { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2377 self.metadataProvider_, | 2465 self.metadataProvider_, |
2378 shareActions, | 2466 shareActions, |
2379 str); | 2467 str); |
2380 }; | 2468 }; |
2381 | 2469 |
2382 galleryFrame.src = 'js/image_editor/gallery.html'; | 2470 galleryFrame.src = 'js/image_editor/gallery.html'; |
2383 this.dialogDom_.appendChild(galleryFrame); | 2471 this.dialogDom_.appendChild(galleryFrame); |
2384 galleryFrame.focus(); | 2472 galleryFrame.focus(); |
2385 }; | 2473 }; |
2386 | 2474 |
2475 FileManager.prototype.getRootForPath_ = function(path) { | |
2476 for (var index = 0; index < this.rootEntries_.length; index++) { | |
2477 if (isParentPath(this.rootEntries_[index].fullPath, path)) { | |
2478 return index; | |
2479 } | |
2480 } | |
2481 return -1; | |
2482 }; | |
2483 | |
2387 /** | 2484 /** |
2388 * Update the breadcrumb display to reflect the current directory. | 2485 * Update the breadcrumb display to reflect the current directory. |
2389 */ | 2486 */ |
2390 FileManager.prototype.updateBreadcrumbs_ = function() { | 2487 FileManager.prototype.updateBreadcrumbs_ = function() { |
2391 var bc = this.dialogDom_.querySelector('.breadcrumbs'); | 2488 var bc = this.dialogDom_.querySelector('.breadcrumbs'); |
2392 bc.innerHTML = ''; | 2489 bc.innerHTML = ''; |
2393 | 2490 |
2394 var fullPath = this.currentDirEntry_.fullPath.replace(/\/$/, ''); | 2491 var fullPath = this.currentDirEntry_.fullPath; |
2395 var pathNames = fullPath.split('/'); | 2492 var rootIndex = this.getRootForPath_(fullPath); |
2396 var path = ''; | 2493 if (rootIndex == -1) { |
2494 console.error('Not root for: ' + fullPath); | |
2495 return; | |
2496 } | |
2497 var root = this.rootEntries_[rootIndex]; | |
2498 | |
2499 var icon = this.document_.createElement('img'); | |
2500 icon.className = 'breadcrumb-icon'; | |
2501 icon.setAttribute('src', this.getRootIconUrl_(root.fullPath, true)); | |
2502 bc.appendChild(icon); | |
2503 | |
2504 var rootPath = root.fullPath; | |
2505 var relativePath = fullPath.substring(rootPath.length); | |
2506 var pathNames = relativePath.replace(/\/$/, '').split('/'); | |
2507 if (pathNames[0] == '') | |
2508 pathNames.splice(0, 1); | |
2509 | |
2510 // We need a first breadcrumb for root, so placing last name from | |
2511 // rootPath as first name of relativePath. | |
2512 var rootPathNames = rootPath.replace(/\/$/, '').split('/'); | |
2513 pathNames.splice(0, 0, rootPathNames[rootPathNames.length - 1]); | |
2514 rootPathNames.splice(rootPathNames.length - 1, 1); | |
2515 var path = rootPathNames.join('/') + '/'; | |
2397 | 2516 |
2398 for (var i = 0; i < pathNames.length; i++) { | 2517 for (var i = 0; i < pathNames.length; i++) { |
2399 var pathName = pathNames[i]; | 2518 var pathName = pathNames[i]; |
2400 path += pathName + '/'; | 2519 path += pathName; |
2401 | 2520 |
2402 var div = this.document_.createElement('div'); | 2521 var div = this.document_.createElement('div'); |
2403 div.className = 'breadcrumb-path'; | 2522 div.className = 'breadcrumb-path'; |
2404 if (i <= 1) { | 2523 div.textContent = i == 0 ? this.getRootLabel_(path) : pathName; |
2405 // i == 0: root directory itself, i == 1: the files it contains. | |
2406 div.textContent = this.getLabelForRootPath_(pathName); | |
2407 } else { | |
2408 div.textContent = pathName; | |
2409 } | |
2410 | 2524 |
2525 path = path + '/'; | |
2411 div.path = path; | 2526 div.path = path; |
2412 div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); | 2527 div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); |
2413 | 2528 |
2414 bc.appendChild(div); | 2529 bc.appendChild(div); |
2415 | 2530 |
2416 if (i == pathNames.length - 1) { | 2531 if (i == pathNames.length - 1) { |
2417 div.classList.add('breadcrumb-last'); | 2532 div.classList.add('breadcrumb-last'); |
2418 } else { | 2533 } else { |
2419 var spacer = this.document_.createElement('div'); | 2534 var spacer = this.document_.createElement('div'); |
2420 spacer.className = 'breadcrumb-spacer'; | 2535 spacer.className = 'breadcrumb-spacer'; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2500 for (var i = 0; i < this.dataModel_.length; i++) { | 2615 for (var i = 0; i < this.dataModel_.length; i++) { |
2501 if (this.dataModel_.item(i).name == name) { | 2616 if (this.dataModel_.item(i).name == name) { |
2502 this.currentList_.selectionModel.selectedIndex = i; | 2617 this.currentList_.selectionModel.selectedIndex = i; |
2503 this.currentList_.scrollIndexIntoView(i); | 2618 this.currentList_.scrollIndexIntoView(i); |
2504 this.currentList_.focus(); | 2619 this.currentList_.focus(); |
2505 return; | 2620 return; |
2506 } | 2621 } |
2507 } | 2622 } |
2508 }; | 2623 }; |
2509 | 2624 |
2625 FileManager.prototype.updateRootsListSelection_ = function() { | |
2626 if (!this.currentDirEntry_) return; | |
2627 var index = this.getRootForPath_(this.currentDirEntry_.fullPath); | |
2628 if (index == -1) { | |
2629 this.rootsList_.selectionModel.selectedIndex = 0; | |
2630 } else { | |
2631 if (this.rootsList_.selectionModel.selectedIndex != index) | |
2632 this.rootsList_.selectionModel.selectedIndex = index; | |
2633 } | |
2634 }; | |
2635 | |
2510 /** | 2636 /** |
2511 * Add the file/directory with given name to the current selection. | 2637 * Add the file/directory with given name to the current selection. |
2512 * | 2638 * |
2513 * @param {string} name The name of the entry to select. | 2639 * @param {string} name The name of the entry to select. |
2514 * @return {boolean} Whether entry exists. | 2640 * @return {boolean} Whether entry exists. |
2515 */ | 2641 */ |
2516 FileManager.prototype.addItemToSelection = function(name) { | 2642 FileManager.prototype.addItemToSelection = function(name) { |
2517 var entryExists = false; | 2643 var entryExists = false; |
2518 for (var i = 0; i < this.dataModel_.length; i++) { | 2644 for (var i = 0; i < this.dataModel_.length; i++) { |
2519 if (this.dataModel_.item(i).name == name) { | 2645 if (this.dataModel_.item(i).name == name) { |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2615 FileManager.prototype.changeDirectoryEntry = function(dirEntry, | 2741 FileManager.prototype.changeDirectoryEntry = function(dirEntry, |
2616 opt_saveHistory, | 2742 opt_saveHistory, |
2617 opt_selectedEntry, | 2743 opt_selectedEntry, |
2618 opt_callback) { | 2744 opt_callback) { |
2619 if (typeof opt_saveHistory == 'undefined') { | 2745 if (typeof opt_saveHistory == 'undefined') { |
2620 opt_saveHistory = true; | 2746 opt_saveHistory = true; |
2621 } else { | 2747 } else { |
2622 opt_saveHistory = !!opt_saveHistory; | 2748 opt_saveHistory = !!opt_saveHistory; |
2623 } | 2749 } |
2624 | 2750 |
2751 // Some directories are above roots, so we instead show the first root. | |
2752 // There may be request to change directory above the roots. For example, | |
2753 // when usb-dirve is removed, we try to change to the parent directory, | |
2754 // which is REMOVABLE_DIRECTORY. | |
2755 if (!dirEntry || dirEntry.fullPath == '/' || | |
2756 dirEntry.fullPath == REMOVABLE_DIRECTORY || | |
2757 dirEntry.fullPath == ARCHIVE_DIRECTORY) { | |
2758 dirEntry = this.rootEntries_[0] || dirEntry; | |
2759 } | |
2760 | |
2625 var location = document.location.origin + document.location.pathname + '#' + | 2761 var location = document.location.origin + document.location.pathname + '#' + |
2626 encodeURI(dirEntry.fullPath); | 2762 encodeURI(dirEntry.fullPath); |
2627 if (opt_saveHistory) { | 2763 if (opt_saveHistory) { |
2628 history.pushState(undefined, dirEntry.fullPath, location); | 2764 history.pushState(undefined, dirEntry.fullPath, location); |
2629 } else if (window.location.hash != location) { | 2765 } else if (window.location.hash != location) { |
2630 // If the user typed URL manually that is not canonical it would be fixed | 2766 // If the user typed URL manually that is not canonical it would be fixed |
2631 // here. However it seems history.replaceState doesn't work properly | 2767 // here. However it seems history.replaceState doesn't work properly |
2632 // with rewritable URLs (while does with history.pushState). It changes | 2768 // with rewritable URLs (while does with history.pushState). It changes |
2633 // window.location but doesn't change content of the ombibox. | 2769 // window.location but doesn't change content of the ombibox. |
2634 history.replaceState(undefined, dirEntry.fullPath, location); | 2770 history.replaceState(undefined, dirEntry.fullPath, location); |
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2852 // then the default action of this click event fires and toggles the | 2988 // then the default action of this click event fires and toggles the |
2853 // checkbox back off. | 2989 // checkbox back off. |
2854 // | 2990 // |
2855 // Since we're going to force checkboxes into the correct state for any | 2991 // Since we're going to force checkboxes into the correct state for any |
2856 // multi-selection, we can prevent this shift click from toggling the | 2992 // multi-selection, we can prevent this shift click from toggling the |
2857 // checkbox and avoid the trouble. | 2993 // checkbox and avoid the trouble. |
2858 event.preventDefault(); | 2994 event.preventDefault(); |
2859 } | 2995 } |
2860 }; | 2996 }; |
2861 | 2997 |
2998 FileManager.prototype.onRootsSelectionChanged_ = function(event) { | |
2999 var root = this.rootEntries_[this.rootsList_.selectionModel.selectedIndex]; | |
3000 this.changeDirectoryEntry(root); | |
3001 }; | |
3002 | |
3003 FileManager.prototype.selectDefaultPathInFilenameInput_ = function() { | |
3004 var input = this.filenameInput_; | |
3005 input.focus(); | |
3006 var selectionEnd = input.value.lastIndexOf('.'); | |
3007 if (selectionEnd == -1) { | |
3008 input.select(); | |
3009 } else { | |
3010 input.selectionStart = 0; | |
3011 input.selectionEnd = selectionEnd; | |
3012 } | |
3013 // Clear, so we never do this again. | |
3014 this.params_.defaultPath = ''; | |
3015 }; | |
3016 | |
2862 /** | 3017 /** |
2863 * Update the UI when the selection model changes. | 3018 * Update the UI when the selection model changes. |
2864 * | 3019 * |
2865 * @param {cr.Event} event The change event. | 3020 * @param {cr.Event} event The change event. |
2866 */ | 3021 */ |
2867 FileManager.prototype.onSelectionChanged_ = function(event) { | 3022 FileManager.prototype.onSelectionChanged_ = function(event) { |
2868 this.summarizeSelection_(); | 3023 this.summarizeSelection_(); |
2869 | 3024 |
2870 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { | 3025 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { |
2871 // If this is a save-as dialog, copy the selected file into the filename | 3026 // If this is a save-as dialog, copy the selected file into the filename |
2872 // input text box. | 3027 // input text box. |
2873 | 3028 |
2874 if (this.selection && | 3029 if (this.selection && |
2875 this.selection.totalCount == 1 && | 3030 this.selection.totalCount == 1 && |
2876 this.selection.entries[0].isFile) | 3031 this.selection.entries[0].isFile && |
3032 this.filenameInput_.value != this.selection.entries[0].name) { | |
2877 this.filenameInput_.value = this.selection.entries[0].name; | 3033 this.filenameInput_.value = this.selection.entries[0].name; |
3034 if (this.params_.defaultPath == this.selection.entries[0].fullPath) | |
3035 this.selectDefaultPathInFilenameInput_(); | |
3036 } | |
2878 } | 3037 } |
2879 | 3038 |
2880 this.updateOkButton_(); | 3039 this.updateOkButton_(); |
2881 | 3040 |
2882 var self = this; | 3041 var self = this; |
2883 setTimeout(function() { self.onSelectionChangeComplete_(event) }, 0); | 3042 setTimeout(function() { self.onSelectionChangeComplete_(event) }, 0); |
2884 }; | 3043 }; |
2885 | 3044 |
2886 /** | 3045 /** |
2887 * Handle selection change related tasks that won't run properly during | 3046 * Handle selection change related tasks that won't run properly during |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3020 * Update the UI when the current directory changes. | 3179 * Update the UI when the current directory changes. |
3021 * | 3180 * |
3022 * @param {cr.Event} event The directory-changed event. | 3181 * @param {cr.Event} event The directory-changed event. |
3023 */ | 3182 */ |
3024 FileManager.prototype.onDirectoryChanged_ = function(event) { | 3183 FileManager.prototype.onDirectoryChanged_ = function(event) { |
3025 this.updateCommands_(); | 3184 this.updateCommands_(); |
3026 this.updateOkButton_(); | 3185 this.updateOkButton_(); |
3027 | 3186 |
3028 this.checkFreeSpace_(this.currentDirEntry_.fullPath); | 3187 this.checkFreeSpace_(this.currentDirEntry_.fullPath); |
3029 | 3188 |
3030 // New folder should never be enabled in the root or media/ directories. | 3189 // TODO(dgozman): title may be better than this. |
3031 this.newFolderButton_.disabled = isSystemDirEntry(this.currentDirEntry_); | |
3032 | |
3033 this.document_.title = this.currentDirEntry_.fullPath; | 3190 this.document_.title = this.currentDirEntry_.fullPath; |
3034 | 3191 |
3035 var self = this; | 3192 var self = this; |
3036 | 3193 |
3037 if (this.subscribedOnDirectoryChanges_) { | 3194 if (this.subscribedOnDirectoryChanges_) { |
3038 chrome.fileBrowserPrivate.removeFileWatch(event.previousDirEntry.toURL(), | 3195 chrome.fileBrowserPrivate.removeFileWatch(event.previousDirEntry.toURL(), |
3039 function(result) { | 3196 function(result) { |
3040 if (!result) { | 3197 if (!result) { |
3041 console.log('Failed to remove file watch'); | 3198 console.log('Failed to remove file watch'); |
3042 } | 3199 } |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3118 // Updated when a user clicks on the label of a file, used to detect | 3275 // Updated when a user clicks on the label of a file, used to detect |
3119 // when a click is eligible to trigger a rename. Can be null, or | 3276 // when a click is eligible to trigger a rename. Can be null, or |
3120 // an object with 'path' and 'date' properties. | 3277 // an object with 'path' and 'date' properties. |
3121 this.lastLabelClick_ = null; | 3278 this.lastLabelClick_ = null; |
3122 | 3279 |
3123 // Clear the table first. | 3280 // Clear the table first. |
3124 this.dataModel_.splice(0, this.dataModel_.length); | 3281 this.dataModel_.splice(0, this.dataModel_.length); |
3125 this.currentList_.selectionModel.clear(); | 3282 this.currentList_.selectionModel.clear(); |
3126 | 3283 |
3127 this.updateBreadcrumbs_(); | 3284 this.updateBreadcrumbs_(); |
3285 this.updateRootsListSelection_(); | |
3128 | 3286 |
3129 if (this.currentDirEntry_.fullPath != '/') { | 3287 // Add current request to pending result list |
3130 // Add current request to pending result list | 3288 this.pendingRescanQueue_.push({ |
3131 this.pendingRescanQueue_.push({ | 3289 onSuccess:opt_callback, |
3132 onSuccess:opt_callback, | 3290 onError:opt_onError |
3133 onError:opt_onError | 3291 }); |
3134 }); | |
3135 | 3292 |
3136 if (this.rescanRunning_) | 3293 if (this.rescanRunning_) |
3137 return; | 3294 return; |
3138 | 3295 |
3139 this.rescanRunning_ = true; | 3296 this.rescanRunning_ = true; |
3140 | 3297 |
3141 // The current list of callbacks is saved and reset. Subsequent | 3298 // The current list of callbacks is saved and reset. Subsequent |
3142 // calls to rescanDirectory_ while we're still pending will be | 3299 // calls to rescanDirectory_ while we're still pending will be |
3143 // saved and will cause an additional rescan to happen after a delay. | 3300 // saved and will cause an additional rescan to happen after a delay. |
3144 var callbacks = this.pendingRescanQueue_; | 3301 var callbacks = this.pendingRescanQueue_; |
3145 | 3302 |
3146 this.pendingRescanQueue_ = []; | 3303 this.pendingRescanQueue_ = []; |
3147 | 3304 |
3148 var self = this; | 3305 var self = this; |
3149 var reader; | 3306 var reader; |
3150 | 3307 |
3151 function onError() { | 3308 function onError() { |
3309 if (self.pendingRescanQueue_.length > 0) { | |
3310 setTimeout(self.rescanDirectory_.bind(self), | |
3311 SIMULTANEOUS_RESCAN_INTERVAL); | |
3312 } | |
3313 | |
3314 self.rescanRunning_ = false; | |
3315 | |
3316 for (var i= 0; i < callbacks.length; i++) { | |
3317 if (callbacks[i].onError) | |
3318 try { | |
3319 callbacks[i].onError(); | |
3320 } catch (ex) { | |
3321 console.error('Caught exception while notifying about error: ' + | |
3322 name, ex); | |
3323 } | |
3324 } | |
3325 } | |
3326 | |
3327 function onReadSome(entries) { | |
3328 if (entries.length == 0) { | |
3329 metrics.recordTime('DirectoryScan'); | |
3330 if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) { | |
3331 metrics.reportCount("DownloadsCount", self.dataModel_.length); | |
3332 } | |
3333 | |
3152 if (self.pendingRescanQueue_.length > 0) { | 3334 if (self.pendingRescanQueue_.length > 0) { |
3153 setTimeout(self.rescanDirectory_.bind(self), | 3335 setTimeout(self.rescanDirectory_.bind(self), |
3154 SIMULTANEOUS_RESCAN_INTERVAL); | 3336 SIMULTANEOUS_RESCAN_INTERVAL); |
3155 } | 3337 } |
3156 | 3338 |
3157 self.rescanRunning_ = false; | 3339 self.rescanRunning_ = false; |
3158 | |
3159 for (var i= 0; i < callbacks.length; i++) { | 3340 for (var i= 0; i < callbacks.length; i++) { |
3160 if (callbacks[i].onError) | 3341 if (callbacks[i].onSuccess) |
3161 try { | 3342 try { |
3162 callbacks[i].onError(); | 3343 callbacks[i].onSuccess(); |
3163 } catch (ex) { | 3344 } catch (ex) { |
3164 console.error('Caught exception while notifying about error: ' + | 3345 console.error('Caught exception while notifying about error: ' + |
3165 name, ex); | 3346 name, ex); |
3166 } | 3347 } |
3167 } | 3348 } |
3349 | |
3350 return; | |
3168 } | 3351 } |
3169 | 3352 |
3170 function onReadSome(entries) { | 3353 // Splice takes the to-be-spliced-in array as individual parameters, |
3171 if (entries.length == 0) { | 3354 // rather than as an array, so we need to perform some acrobatics... |
3172 metrics.recordTime('DirectoryScan'); | 3355 var spliceArgs = [].slice.call(entries); |
3173 if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) { | |
3174 metrics.reportCount("DownloadsCount", self.dataModel_.length); | |
3175 } | |
3176 | 3356 |
3177 if (self.pendingRescanQueue_.length > 0) { | 3357 // Hide files that start with a dot ('.'). |
3178 setTimeout(self.rescanDirectory_.bind(self), | 3358 // TODO(rginda): User should be able to override this. Support for other |
3179 SIMULTANEOUS_RESCAN_INTERVAL); | 3359 // commonly hidden patterns might be nice too. |
3180 } | 3360 if (self.filterFiles_) { |
3361 spliceArgs = spliceArgs.filter(function(e) { | |
3362 return e.name.substr(0, 1) != '.'; | |
3363 }); | |
3364 } | |
3181 | 3365 |
3182 self.rescanRunning_ = false; | 3366 spliceArgs.unshift(0, 0); // index, deleteCount |
3183 for (var i= 0; i < callbacks.length; i++) { | 3367 self.dataModel_.splice.apply(self.dataModel_, spliceArgs); |
3184 if (callbacks[i].onSuccess) | |
3185 try { | |
3186 callbacks[i].onSuccess(); | |
3187 } catch (ex) { | |
3188 console.error('Caught exception while notifying about error: ' + | |
3189 name, ex); | |
3190 } | |
3191 } | |
3192 | 3368 |
3193 return; | 3369 // Keep reading until entries.length is 0. |
3194 } | 3370 reader.readEntries(onReadSome, onError); |
3371 }; | |
3195 | 3372 |
3196 // Splice takes the to-be-spliced-in array as individual parameters, | 3373 metrics.startInterval('DirectoryScan'); |
3197 // rather than as an array, so we need to perform some acrobatics... | |
3198 var spliceArgs = [].slice.call(entries); | |
3199 | 3374 |
3200 // Hide files that start with a dot ('.'). | 3375 // If not the root directory, just read the contents. |
3201 // TODO(rginda): User should be able to override this. Support for other | 3376 reader = this.currentDirEntry_.createReader(); |
3202 // commonly hidden patterns might be nice too. | 3377 reader.readEntries(onReadSome, onError); |
3203 if (self.filterFiles_) { | |
3204 spliceArgs = spliceArgs.filter(function(e) { | |
3205 return e.name.substr(0, 1) != '.'; | |
3206 }); | |
3207 } | |
3208 | |
3209 spliceArgs.unshift(0, 0); // index, deleteCount | |
3210 self.dataModel_.splice.apply(self.dataModel_, spliceArgs); | |
3211 | |
3212 // Keep reading until entries.length is 0. | |
3213 reader.readEntries(onReadSome, onError); | |
3214 }; | |
3215 | |
3216 metrics.startInterval('DirectoryScan'); | |
3217 | |
3218 // If not the root directory, just read the contents. | |
3219 reader = this.currentDirEntry_.createReader(); | |
3220 reader.readEntries(onReadSome, onError); | |
3221 return; | |
3222 } | |
3223 | |
3224 // Otherwise, use the provided list of root subdirectories, since the | |
3225 // real local filesystem root directory (the one we use outside the | |
3226 // harness) can't be enumerated yet. | |
3227 var spliceArgs = [].slice.call(this.rootEntries_); | |
3228 spliceArgs.unshift(0, 0); // index, deleteCount | |
3229 this.dataModel_.splice.apply(this.dataModel_, spliceArgs); | |
3230 | |
3231 if (opt_callback) | |
3232 opt_callback(); | |
3233 }; | 3378 }; |
3234 | 3379 |
3235 FileManager.prototype.findListItem_ = function(event) { | 3380 FileManager.prototype.findListItem_ = function(event) { |
3236 var node = event.srcElement; | 3381 var node = event.srcElement; |
3237 while (node) { | 3382 while (node) { |
3238 if (node.tagName == 'LI') | 3383 if (node.tagName == 'LI') |
3239 break; | 3384 break; |
3240 node = node.parentNode; | 3385 node = node.parentNode; |
3241 } | 3386 } |
3242 | 3387 |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3466 var selectionEnd = input.value.lastIndexOf('.'); | 3611 var selectionEnd = input.value.lastIndexOf('.'); |
3467 if (selectionEnd == -1) { | 3612 if (selectionEnd == -1) { |
3468 input.select(); | 3613 input.select(); |
3469 } else { | 3614 } else { |
3470 input.selectionStart = 0; | 3615 input.selectionStart = 0; |
3471 input.selectionEnd = selectionEnd; | 3616 input.selectionEnd = selectionEnd; |
3472 } | 3617 } |
3473 }, 0); | 3618 }, 0); |
3474 }; | 3619 }; |
3475 | 3620 |
3476 FileManager.prototype.onNewFolderButtonClick_ = function(event) { | 3621 FileManager.prototype.onToggleSidebar_ = function(event) { |
3622 if (this.dialogContainer_.hasAttribute('sidebar')) { | |
3623 this.dialogContainer_.removeAttribute('sidebar'); | |
3624 } else { | |
3625 this.dialogContainer_.setAttribute('sidebar', 'sidebar'); | |
3626 } | |
3627 // TODO(dgozman): make table header css-resizable. | |
3628 setTimeout(this.onResize_.bind(this), 300); | |
3629 }; | |
3630 | |
3631 FileManager.prototype.onNewFolderCommand_ = function(event) { | |
3477 var self = this; | 3632 var self = this; |
3478 | 3633 |
3479 function onNameSelected(name) { | 3634 function onNameSelected(name) { |
3480 var valid = self.validateFileName_(name, function() { | 3635 var valid = self.validateFileName_(name, function() { |
3481 promptForName(name); | 3636 promptForName(name); |
3482 }); | 3637 }); |
3483 | 3638 |
3484 if (!valid) { | 3639 if (!valid) { |
3485 // Validation failed. User will be prompted for a new name after they | 3640 // Validation failed. User will be prompted for a new name after they |
3486 // dismiss the validation error dialog. | 3641 // dismiss the validation error dialog. |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3595 this.dialogType_ != FileManager.SELECT_FOLDER) { | 3750 this.dialogType_ != FileManager.SELECT_FOLDER) { |
3596 event.preventDefault(); | 3751 event.preventDefault(); |
3597 this.onDirectoryAction(this.selection.entries[0]); | 3752 this.onDirectoryAction(this.selection.entries[0]); |
3598 } else if (!this.okButton_.disabled) { | 3753 } else if (!this.okButton_.disabled) { |
3599 event.preventDefault(); | 3754 event.preventDefault(); |
3600 this.onOk_(); | 3755 this.onOk_(); |
3601 } | 3756 } |
3602 break; | 3757 break; |
3603 | 3758 |
3604 case 32: // Ctrl-Space => New Folder. | 3759 case 32: // Ctrl-Space => New Folder. |
3605 if (this.newFolderButton_.style.display != 'none' && event.ctrlKey) { | 3760 if ((this.dialogType_ == 'saveas-file' || |
3761 this.dialogType_ == 'full-page') && event.ctrlKey) { | |
3606 event.preventDefault(); | 3762 event.preventDefault(); |
3607 this.onNewFolderButtonClick_(); | 3763 this.onNewFolderCommand_(); |
3608 } | 3764 } |
3609 break; | 3765 break; |
3610 | 3766 |
3611 case 88: // Ctrl-X => Cut. | 3767 case 88: // Ctrl-X => Cut. |
3612 this.updateCommands_(); | 3768 this.updateCommands_(); |
3613 if (!this.commands_['cut'].disabled) { | 3769 if (!this.commands_['cut'].disabled) { |
3614 event.preventDefault(); | 3770 event.preventDefault(); |
3615 this.commands_['cut'].execute(); | 3771 this.commands_['cut'].execute(); |
3616 } | 3772 } |
3617 break; | 3773 break; |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3926 }); | 4082 }); |
3927 }, onError); | 4083 }, onError); |
3928 | 4084 |
3929 function onError(err) { | 4085 function onError(err) { |
3930 console.log('Error while checking free space: ' + err); | 4086 console.log('Error while checking free space: ' + err); |
3931 setTimeout(doCheck, 1000 * 60); | 4087 setTimeout(doCheck, 1000 * 60); |
3932 } | 4088 } |
3933 } | 4089 } |
3934 } | 4090 } |
3935 })(); | 4091 })(); |
OLD | NEW |