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

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

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

Powered by Google App Engine
This is Rietveld 408576698