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