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