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

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

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

Powered by Google App Engine
This is Rietveld 408576698