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

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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 metrics.recordEnum('Create', this.dialogType_, 58 metrics.recordEnum('Create', this.dialogType_,
59 [FileManager.DialogType.SELECT_FOLDER, 59 [FileManager.DialogType.SELECT_FOLDER,
60 FileManager.DialogType.SELECT_SAVEAS_FILE, 60 FileManager.DialogType.SELECT_SAVEAS_FILE,
61 FileManager.DialogType.SELECT_OPEN_FILE, 61 FileManager.DialogType.SELECT_OPEN_FILE,
62 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, 62 FileManager.DialogType.SELECT_OPEN_MULTI_FILE,
63 FileManager.DialogType.FULL_PAGE]); 63 FileManager.DialogType.FULL_PAGE]);
64 64
65 // TODO(dgozman): This will be changed to LocaleInfo. 65 // TODO(dgozman): This will be changed to LocaleInfo.
66 this.locale_ = new v8Locale(navigator.language); 66 this.locale_ = new v8Locale(navigator.language);
67 67
68 this.resolveRoots_(); 68 this.initFileSystem_();
69 this.initDom_(); 69 this.initDom_();
70 this.initDialogType_(); 70 this.initDialogType_();
71 this.dialogDom_.style.opacity = '1'; 71 this.dialogDom_.style.opacity = '1';
72 } 72 }
73 73
74 FileManager.prototype = { 74 FileManager.prototype = {
75 __proto__: cr.EventTarget.prototype 75 __proto__: cr.EventTarget.prototype
76 }; 76 };
77 77
78 // Anonymous "namespace". 78 // Anonymous "namespace".
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after
460 chrome.fileBrowserPrivate.getStrings(function(strings) { 460 chrome.fileBrowserPrivate.getStrings(function(strings) {
461 localStrings = new LocalStrings(strings); 461 localStrings = new LocalStrings(strings);
462 if (callback) 462 if (callback)
463 callback(); 463 callback();
464 }); 464 });
465 }; 465 };
466 466
467 // Instance methods. 467 // Instance methods.
468 468
469 /** 469 /**
470 * Request file system and get root entries asynchronously. Invokes init_ 470 * Request local file system, resolve roots and init_ after that.
471 * when have finished.
472 */ 471 */
473 FileManager.prototype.resolveRoots_ = function(callback) { 472 FileManager.prototype.initFileSystem_ = function() {
474 var rootPaths = ['Downloads', 'removable', 'archive']; 473 util.installFileErrorToString();
474 metrics.startInterval('RequestLocalFileSystem');
475 475
476 metrics.startInterval('RequestLocalFileSystem');
477 var self = this; 476 var self = this;
478 477
479 // The list of active mount points to distinct them from other directories. 478 // The list of active mount points to distinct them from other directories.
480 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { 479 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) {
481 self.mountPoints_ = mountPoints; 480 self.mountPoints_ = mountPoints;
482 onDone(); 481 onDone();
483 }); 482 });
484 483
485 function onDone() { 484 function onDone() {
486 if (self.mountPoints_ && self.rootEntries_) 485 if (self.mountPoints_ && self.rootEntries_)
487 self.init_(); 486 self.init_();
488 } 487 }
489 488
490 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { 489 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) {
491 self.filesystem_ = filesystem;
492 util.installFileErrorToString();
493
494 metrics.recordTime('RequestLocalFileSystem'); 490 metrics.recordTime('RequestLocalFileSystem');
495 console.log('Found filesystem: ' + filesystem.name, filesystem); 491 console.log('Found filesystem: ' + filesystem.name, filesystem);
496 492
497 var rootEntries = []; 493 self.filesystem_ = filesystem;
498 494 self.resolveRoots_(function(rootEntries) {
499 function onAllRootsFound() {
500 self.rootEntries_ = rootEntries; 495 self.rootEntries_ = rootEntries;
501 onDone(); 496 onDone();
502 } 497 });
503
504 function onPathError(path, err) {
505 console.error('Error locating root path: ' + path + ': ' + err);
506 }
507
508 function onEntryFound(entry) {
509 if (entry) {
510 rootEntries.push(entry);
511 } else {
512 onAllRootsFound();
513 }
514 }
515
516 metrics.startInterval('EnumerateRoots');
517 if (filesystem.name.match(/^chrome-extension_\S+:external/i)) {
518 // We've been handed the local filesystem, whose root directory
519 // cannot be enumerated.
520 util.getDirectories(filesystem.root, {create: false}, rootPaths,
521 onEntryFound, onPathError);
522 } else {
523 util.forEachDirEntry(filesystem.root, onEntryFound);
524 }
525 }); 498 });
526 }; 499 };
527 500
528 /** 501 /**
502 * Get root entries asynchronously. Invokes callback
503 * when have finished.
504 */
505 FileManager.prototype.resolveRoots_ = function(callback) {
506 var rootPaths = [DOWNLOADS_DIRECTORY, ARCHIVE_DIRECTORY,
507 REMOVABLE_DIRECTORY].map(function(s) { return s.substring(1); });
508 var rootEntries = [];
509
510 // The number of entries left to enumerate to get all roots.
511 // When equals to zero, we are done.
512 var entriesToEnumerate = 0;
513 // Entries may be enumerated faster than next one appears, so we have this
514 // guard to not finish too early.
515 var allEntriesFound = false;
516
517 function onPathError(path, err) {
518 console.error('Error locating root path: ' + path + ': ' + err);
519 }
520
521 function onRootFound(root) {
522 if (root) {
523 rootEntries.push(root);
524 } else {
525 entriesToEnumerate--;
526 if (entriesToEnumerate == 0 && allEntriesFound) {
527 metrics.recordTime('EnumerateRoots');
528 callback(rootEntries);
529 }
530 }
531 }
532
533 function onEntryFound(entry) {
534 if (entry) {
535 entriesToEnumerate++;
536 var path = entry.fullPath;
537 if (path == ARCHIVE_DIRECTORY || path == REMOVABLE_DIRECTORY) {
538 // All removable devices and mounted archives are considered
539 // roots, and are shown in the sidebar.
540 util.forEachDirEntry(entry, onRootFound);
541 } else {
542 onRootFound(entry);
543 onRootFound(null);
544 }
545 } else {
546 allEntriesFound = true;
547 }
548 }
549
550 metrics.startInterval('EnumerateRoots');
551 if (this.filesystem_.name.match(/^chrome-extension_\S+:external/i)) {
552 // We've been handed the local filesystem, whose root directory
553 // cannot be enumerated.
554 util.getDirectories(this.filesystem_.root, {create: false}, rootPaths,
555 onEntryFound, onPathError);
556 } else {
557 util.forEachDirEntry(this.filesystem_.root, onEntryFound);
558 }
559 };
560
561 /**
529 * Continue initializing the file manager after resolving roots. 562 * Continue initializing the file manager after resolving roots.
530 */ 563 */
531 FileManager.prototype.init_ = function() { 564 FileManager.prototype.init_ = function() {
532 metrics.startInterval('InitFileManager'); 565 metrics.startInterval('InitFileManager');
566 this.initCommands_();
533 567
534 // TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is 568 // TODO(rginda): 6/22/11: Remove this test when createDateTimeFormat is
535 // available in all chrome trunk builds. 569 // available in all chrome trunk builds.
536 if ('createDateTimeFormat' in this.locale_) { 570 if ('createDateTimeFormat' in this.locale_) {
537 this.shortDateFormatter_ = 571 this.shortDateFormatter_ =
538 this.locale_.createDateTimeFormat({'dateType': 'medium'}); 572 this.locale_.createDateTimeFormat({'dateType': 'medium'});
539 } else { 573 } else {
540 this.shortDateFormatter_ = { 574 this.shortDateFormatter_ = {
541 format: function(d) { 575 format: function(d) {
542 return (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear(); 576 return (d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear();
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 window.addEventListener('unload', this.onUnload_.bind(this)); 614 window.addEventListener('unload', this.onUnload_.bind(this));
581 615
582 this.addEventListener('directory-changed', 616 this.addEventListener('directory-changed',
583 this.onDirectoryChanged_.bind(this)); 617 this.onDirectoryChanged_.bind(this));
584 this.addEventListener('selection-summarized', 618 this.addEventListener('selection-summarized',
585 this.onSelectionSummarized_.bind(this)); 619 this.onSelectionSummarized_.bind(this));
586 620
587 // The list of archives requested to mount. We will show contents once 621 // The list of archives requested to mount. We will show contents once
588 // archive is mounted, but only for mounts from within this filebrowser tab. 622 // archive is mounted, but only for mounts from within this filebrowser tab.
589 this.mountRequests_ = []; 623 this.mountRequests_ = [];
624 this.unmountRequests_ = [];
590 chrome.fileBrowserPrivate.onMountCompleted.addListener( 625 chrome.fileBrowserPrivate.onMountCompleted.addListener(
591 this.onMountCompleted_.bind(this)); 626 this.onMountCompleted_.bind(this));
592 627
593 chrome.fileBrowserPrivate.onFileChanged.addListener( 628 chrome.fileBrowserPrivate.onFileChanged.addListener(
594 this.onFileChanged_.bind(this)); 629 this.onFileChanged_.bind(this));
595 630
596 var self = this; 631 var self = this;
597 632
598 // The list of callbacks to be invoked during the directory rescan after 633 // The list of callbacks to be invoked during the directory rescan after
599 // all paste tasks are complete. 634 // all paste tasks are complete.
600 this.pasteSuccessCallbacks_ = []; 635 this.pasteSuccessCallbacks_ = [];
601 636
602 this.initCommands_();
603
604 this.setupCurrentDirectory_(); 637 this.setupCurrentDirectory_();
605 638
606 this.summarizeSelection_(); 639 this.summarizeSelection_();
607 640
608 this.dataModel_.sort('cachedMtime_', 'desc'); 641 this.dataModel_.sort('cachedMtime_', 'desc');
609 642
610 this.refocus(); 643 this.refocus();
611 644
612 this.createMetadataProvider_(); 645 this.createMetadataProvider_();
613 metrics.recordTime('InitFileManager'); 646 metrics.recordTime('InitFileManager');
614 metrics.recordTime('TotalLoad'); 647 metrics.recordTime('TotalLoad');
615 }; 648 };
616 649
617 /** 650 /**
618 * One-time initialization of commands. 651 * One-time initialization of commands.
619 */ 652 */
620 FileManager.prototype.initCommands_ = function() { 653 FileManager.prototype.initCommands_ = function() {
621 var commands = this.dialogDom_.querySelectorAll('command'); 654 var commands = this.dialogDom_.querySelectorAll('command');
622 for (var i = 0; i < commands.length; i++) { 655 for (var i = 0; i < commands.length; i++) {
623 var command = commands[i]; 656 var command = commands[i];
624 cr.ui.Command.decorate(command); 657 cr.ui.Command.decorate(command);
658 command.label = command.textContent;
SeRya 2011/11/28 10:30:55 Right way to int-ze the labes is using 'i18-values
dgozman 2011/11/28 11:45:53 Done.
659 command.textContent = '';
625 this.commands_[command.id] = command; 660 this.commands_[command.id] = command;
626 } 661 }
627 662
628 this.fileContextMenu_ = this.dialogDom_.querySelector('.file-context-menu'); 663 this.fileContextMenu_ = this.dialogDom_.querySelector('.file-context-menu');
629 cr.ui.Menu.decorate(this.fileContextMenu_); 664 cr.ui.Menu.decorate(this.fileContextMenu_);
630 665
631 this.document_.addEventListener('canExecute', 666 this.document_.addEventListener('canExecute',
632 this.onCanExecute_.bind(this)); 667 this.onCanExecute_.bind(this));
633 this.document_.addEventListener('command', this.onCommand_.bind(this)); 668 this.document_.addEventListener('command', this.onCommand_.bind(this));
634 } 669 }
(...skipping 17 matching lines...) Expand all
652 // Cache nodes we'll be manipulating. 687 // Cache nodes we'll be manipulating.
653 this.previewThumbnails_ = 688 this.previewThumbnails_ =
654 this.dialogDom_.querySelector('.preview-thumbnails'); 689 this.dialogDom_.querySelector('.preview-thumbnails');
655 this.previewPanel_ = this.dialogDom_.querySelector('.preview-panel'); 690 this.previewPanel_ = this.dialogDom_.querySelector('.preview-panel');
656 this.previewFilename_ = this.dialogDom_.querySelector('.preview-filename'); 691 this.previewFilename_ = this.dialogDom_.querySelector('.preview-filename');
657 this.previewSummary_ = this.dialogDom_.querySelector('.preview-summary'); 692 this.previewSummary_ = this.dialogDom_.querySelector('.preview-summary');
658 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); 693 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input');
659 this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons'); 694 this.taskButtons_ = this.dialogDom_.querySelector('.task-buttons');
660 this.okButton_ = this.dialogDom_.querySelector('.ok'); 695 this.okButton_ = this.dialogDom_.querySelector('.ok');
661 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); 696 this.cancelButton_ = this.dialogDom_.querySelector('.cancel');
662 this.newFolderButton_ = this.dialogDom_.querySelector('.new-folder');
663 this.deleteButton_ = this.dialogDom_.querySelector('.delete-button'); 697 this.deleteButton_ = this.dialogDom_.querySelector('.delete-button');
664 698
665 this.downloadsWarning_ = 699 this.downloadsWarning_ =
666 this.dialogDom_.querySelector('.downloads-warning'); 700 this.dialogDom_.querySelector('.downloads-warning');
667 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING')); 701 var html = util.htmlUnescape(str('DOWNLOADS_DIRECTORY_WARNING'));
668 this.downloadsWarning_.lastElementChild.innerHTML = html; 702 this.downloadsWarning_.lastElementChild.innerHTML = html;
669 var link = this.downloadsWarning_.querySelector('a'); 703 var link = this.downloadsWarning_.querySelector('a');
670 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this)); 704 link.addEventListener('click', this.onDownloadsWarningClick_.bind(this));
671 705
672 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); 706 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
(...skipping 10 matching lines...) Expand all
683 'keyup', this.onFilenameInputKeyUp_.bind(this)); 717 'keyup', this.onFilenameInputKeyUp_.bind(this));
684 this.filenameInput_.addEventListener( 718 this.filenameInput_.addEventListener(
685 'focus', this.onFilenameInputFocus_.bind(this)); 719 'focus', this.onFilenameInputFocus_.bind(this));
686 720
687 var listContainer = this.dialogDom_.querySelector('.list-container'); 721 var listContainer = this.dialogDom_.querySelector('.list-container');
688 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this)); 722 listContainer.addEventListener('keydown', this.onListKeyDown_.bind(this));
689 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this)); 723 listContainer.addEventListener('keypress', this.onListKeyPress_.bind(this));
690 this.okButton_.addEventListener('click', this.onOk_.bind(this)); 724 this.okButton_.addEventListener('click', this.onOk_.bind(this));
691 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this)); 725 this.cancelButton_.addEventListener('click', this.onCancel_.bind(this));
692 726
693 this.dialogDom_.querySelector('button.new-folder').addEventListener( 727 this.dialogDom_.querySelector('div.open-sidebar').addEventListener(
694 'click', this.onNewFolderButtonClick_.bind(this)); 728 'click', this.onToggleSidebar_.bind(this));
729 this.dialogDom_.querySelector('div.close-sidebar').addEventListener(
730 'click', this.onToggleSidebar_.bind(this));
731 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container');
695 732
696 this.dialogDom_.querySelector('button.detail-view').addEventListener( 733 this.dialogDom_.querySelector('button.detail-view').addEventListener(
697 'click', this.onDetailViewButtonClick_.bind(this)); 734 'click', this.onDetailViewButtonClick_.bind(this));
698 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener( 735 this.dialogDom_.querySelector('button.thumbnail-view').addEventListener(
699 'click', this.onThumbnailViewButtonClick_.bind(this)); 736 'click', this.onThumbnailViewButtonClick_.bind(this));
700 737
701 this.dialogDom_.ownerDocument.defaultView.addEventListener( 738 this.dialogDom_.ownerDocument.defaultView.addEventListener(
702 'resize', this.onResize_.bind(this)); 739 'resize', this.onResize_.bind(this));
703 740
704 var ary = this.dialogDom_.querySelectorAll('[visibleif]'); 741 var ary = this.dialogDom_.querySelectorAll('[visibleif]');
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || 774 if (this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE ||
738 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FOLDER || 775 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FOLDER ||
739 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { 776 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) {
740 this.selectionModelClass_ = cr.ui.ListSingleSelectionModel; 777 this.selectionModelClass_ = cr.ui.ListSingleSelectionModel;
741 } else { 778 } else {
742 this.selectionModelClass_ = cr.ui.ListSelectionModel; 779 this.selectionModelClass_ = cr.ui.ListSelectionModel;
743 } 780 }
744 781
745 this.initTable_(); 782 this.initTable_();
746 this.initGrid_(); 783 this.initGrid_();
784 this.initRootsList_();
747 785
748 this.setListType(FileManager.ListType.DETAIL); 786 this.setListType(FileManager.ListType.DETAIL);
749 787
750 this.onResize_(); 788 this.onResize_();
751 789
752 this.textSearchState_ = {text: '', date: new Date()}; 790 this.textSearchState_ = {text: '', date: new Date()};
753 }; 791 };
754 792
793 FileManager.prototype.initRootsList_ = function() {
794 this.rootsList_ = this.dialogDom_.querySelector('.roots-list');
795 cr.ui.List.decorate(this.rootsList_);
796
797 var self = this;
798 this.rootsList_.itemConstructor = function(entry) {
799 return self.renderRoot_(entry);
800 };
801
802 this.rootsList_.selectionModel = new cr.ui.ListSingleSelectionModel();
803 this.rootsList_.selectionModel.addEventListener(
804 'change', this.onRootsSelectionChanged_.bind(this));
805
806 // TODO(dgozman): add "Add a drive" item.
807 this.rootsList_.dataModel = new cr.ui.ArrayDataModel(this.rootEntries_);
808 };
809
810 FileManager.prototype.updateRoots_ = function(opt_changeDirectoryTo) {
811 var self = this;
812 this.resolveRoots_(function(rootEntries) {
813 self.rootEntries_ = rootEntries;
814
815 var dataModel = self.rootsList_.dataModel;
816 var args = [0, dataModel.length].concat(rootEntries);
817 dataModel.splice.apply(dataModel, args);
818
819 self.updateRootsListSelection_();
820
821 if (opt_changeDirectoryTo)
822 self.changeDirectory(opt_changeDirectoryTo);
823 });
824 };
825
755 /** 826 /**
756 * Get the icon type for a given Entry. 827 * Get the icon type for a given Entry.
757 * 828 *
758 * @param {Entry} entry An Entry subclass (FileEntry or DirectoryEntry). 829 * @param {Entry} entry An Entry subclass (FileEntry or DirectoryEntry).
759 * @return {string} 830 * @return {string}
760 */ 831 */
761 FileManager.prototype.getIconType = function(entry) { 832 FileManager.prototype.getIconType = function(entry) {
762 if (!('cachedIconType_' in entry)) 833 if (!('cachedIconType_' in entry))
763 entry.cachedIconType_ = this.computeIconType_(entry); 834 entry.cachedIconType_ = this.computeIconType_(entry);
764 return entry.cachedIconType_; 835 return entry.cachedIconType_;
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
1064 !isSystemDirEntry(this.currentDirEntry_)); 1135 !isSystemDirEntry(this.currentDirEntry_));
1065 1136
1066 case 'delete': 1137 case 'delete':
1067 return (// Initialized to the point where we have a current directory 1138 return (// Initialized to the point where we have a current directory
1068 this.currentDirEntry_ && 1139 this.currentDirEntry_ &&
1069 // Rename not in progress. 1140 // Rename not in progress.
1070 !this.renameInput_.currentEntry && 1141 !this.renameInput_.currentEntry &&
1071 !isSystemDirEntry(this.currentDirEntry_)) && 1142 !isSystemDirEntry(this.currentDirEntry_)) &&
1072 this.selection && 1143 this.selection &&
1073 this.selection.totalCount > 0; 1144 this.selection.totalCount > 0;
1145
1146 case 'newfolder':
1147 return this.currentDirEntry_ &&
1148 (this.dialogType_ == 'saveas-file' ||
1149 this.dialogType_ == 'full-page');
1074 } 1150 }
1075 }; 1151 };
1076 1152
1077 FileManager.prototype.updateCommonActionButtons_ = function() { 1153 FileManager.prototype.updateCommonActionButtons_ = function() {
1078 if (this.deleteButton_) 1154 if (this.deleteButton_)
1079 this.deleteButton_.disabled = !this.canExecute_('delete'); 1155 this.deleteButton_.disabled = !this.canExecute_('delete');
1080 }; 1156 };
1081 1157
1082 FileManager.prototype.setListType = function(type) { 1158 FileManager.prototype.setListType = function(type) {
1083 if (type && type == this.listType_) 1159 if (type && type == this.listType_)
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
1271 leadIndex); 1347 leadIndex);
1272 return; 1348 return;
1273 } 1349 }
1274 1350
1275 this.initiateRename_(label); 1351 this.initiateRename_(label);
1276 return; 1352 return;
1277 1353
1278 case 'delete': 1354 case 'delete':
1279 this.deleteEntries(this.selection.entries); 1355 this.deleteEntries(this.selection.entries);
1280 return; 1356 return;
1357
1358 case 'newfolder':
1359 this.onNewFolderCommand_(event);
1360 return;
1281 } 1361 }
1282 }; 1362 };
1283 1363
1284 /** 1364 /**
1285 * Respond to the back and forward buttons. 1365 * Respond to the back and forward buttons.
1286 */ 1366 */
1287 FileManager.prototype.onPopState_ = function(event) { 1367 FileManager.prototype.onPopState_ = function(event) {
1288 // TODO(serya): We should restore selected items here. 1368 // TODO(serya): We should restore selected items here.
1289 if (this.rootEntries_) 1369 if (this.rootEntries_)
1290 this.setupCurrentDirectory_(); 1370 this.setupCurrentDirectory_();
1291 }; 1371 };
1292 1372
1293 FileManager.prototype.requestResize_ = function(timeout) { 1373 FileManager.prototype.requestResize_ = function(timeout) {
1294 var self = this; 1374 var self = this;
1295 setTimeout(function() { self.onResize_() }, timeout || 0); 1375 setTimeout(function() { self.onResize_() }, timeout || 0);
1296 }; 1376 };
1297 1377
1298 /** 1378 /**
1299 * Resize details and thumb views to fit the new window size. 1379 * Resize details and thumb views to fit the new window size.
1300 */ 1380 */
1301 FileManager.prototype.onResize_ = function() { 1381 FileManager.prototype.onResize_ = function() {
1302 this.table_.style.height = this.grid_.style.height = 1382 this.table_.style.height = this.grid_.style.height =
1303 this.grid_.parentNode.clientHeight + 'px'; 1383 this.grid_.parentNode.clientHeight + 'px';
1304 this.table_.style.width = this.grid_.style.width =
1305 this.grid_.parentNode.clientWidth + 'px';
1306
1307 this.table_.list_.style.width = this.table_.parentNode.clientWidth + 'px';
1308 this.table_.list_.style.height = (this.table_.clientHeight - 1 - 1384 this.table_.list_.style.height = (this.table_.clientHeight - 1 -
1309 this.table_.header_.clientHeight) + 'px'; 1385 this.table_.header_.clientHeight) + 'px';
1310 1386
1311 if (this.listType_ == FileManager.ListType.THUMBNAIL) { 1387 if (this.listType_ == FileManager.ListType.THUMBNAIL) {
1312 var self = this; 1388 var self = this;
1313 setTimeout(function() { 1389 setTimeout(function() {
1314 self.grid_.columns = 0; 1390 self.grid_.columns = 0;
1315 self.grid_.redraw(); 1391 self.grid_.redraw();
1316 }, 0); 1392 }, 0);
1317 } else { 1393 } else {
1318 this.currentList_.redraw(); 1394 this.currentList_.redraw();
1319 } 1395 }
1396
1397 this.rootsList_.style.height =
1398 this.rootsList_.parentNode.clientHeight + 'px';
1399 this.rootsList_.redraw();
1320 }; 1400 };
1321 1401
1322 FileManager.prototype.resolvePath = function( 1402 FileManager.prototype.resolvePath = function(
1323 path, resultCallback, errorCallback) { 1403 path, resultCallback, errorCallback) {
1324 return util.resolvePath(this.filesystem_.root, path, resultCallback, 1404 return util.resolvePath(this.filesystem_.root, path, resultCallback,
1325 errorCallback); 1405 errorCallback);
1326 }; 1406 };
1327 1407
1328 /** 1408 /**
1329 * Restores current directory and may be a selected item after page load (or 1409 * Restores current directory and may be a selected item after page load (or
(...skipping 13 matching lines...) Expand all
1343 this.setupPath_(this.params_.defaultPath); 1423 this.setupPath_(this.params_.defaultPath);
1344 } else { 1424 } else {
1345 this.setupDefaultPath_(); 1425 this.setupDefaultPath_();
1346 } 1426 }
1347 }; 1427 };
1348 1428
1349 FileManager.prototype.setupDefaultPath_ = function() { 1429 FileManager.prototype.setupDefaultPath_ = function() {
1350 // No preset given, find a good place to start. 1430 // No preset given, find a good place to start.
1351 // Check for removable devices, if there are none, go to Downloads. 1431 // Check for removable devices, if there are none, go to Downloads.
1352 var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) { 1432 var removableDirectoryEntry = this.rootEntries_.filter(function(rootEntry) {
1353 return rootEntry.fullPath == REMOVABLE_DIRECTORY; 1433 return isParentPath(REMOVABLE_DIRECTORY, rootEntry.fullPath);
1354 })[0]; 1434 })[0];
1355 if (!removableDirectoryEntry) { 1435 this.changeDirectory(
1356 this.changeDirectory(DOWNLOADS_DIRECTORY, CD_NO_HISTORY); 1436 removableDirectoryEntry.fullPath || DOWNLOADS_DIRECTORY,
SeRya 2011/11/28 10:30:55 removableDirectoryEntry may be undefined. Access t
dgozman 2011/11/28 11:45:53 Done.
1357 return; 1437 CD_NO_HISTORY);
1358 }
1359
1360 var foundRemovable = false;
1361 util.forEachDirEntry(removableDirectoryEntry, function(result) {
1362 if (result) {
1363 foundRemovable = true;
1364 } else { // Done enumerating, and we know the answer.
1365 this.changeDirectory(foundRemovable ? '/' : DOWNLOADS_DIRECTORY,
1366 CD_NO_HISTORY);
1367 }
1368 }.bind(this));
1369 }; 1438 };
1370 1439
1371 FileManager.prototype.setupPath_ = function(path) { 1440 FileManager.prototype.setupPath_ = function(path) {
1372 // Split the dirname from the basename. 1441 // Split the dirname from the basename.
1373 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/); 1442 var ary = path.match(/^(?:(.*)\/)?([^\/]*)$/);
1374 if (!ary) { 1443 if (!ary) {
1375 console.warn('Unable to split default path: ' + path); 1444 console.warn('Unable to split default path: ' + path);
1376 self.changeDirectory('/', CD_NO_HISTORY); 1445 self.changeDirectory('/', CD_NO_HISTORY);
1377 return; 1446 return;
1378 } 1447 }
(...skipping 16 matching lines...) Expand all
1395 return; 1464 return;
1396 } 1465 }
1397 1466
1398 // Leaf is an existing file, cd to its parent directory and select it. 1467 // Leaf is an existing file, cd to its parent directory and select it.
1399 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY, leafEntry.name); 1468 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY, leafEntry.name);
1400 } 1469 }
1401 1470
1402 function onLeafError(err) { 1471 function onLeafError(err) {
1403 // Set filename first so OK button will update in changeDirectoryEntry. 1472 // Set filename first so OK button will update in changeDirectoryEntry.
1404 self.filenameInput_.value = leafName; 1473 self.filenameInput_.value = leafName;
1474 self.selectDefaultPathInFilenameInput_();
1405 if (err = FileError.NOT_FOUND_ERR) { 1475 if (err = FileError.NOT_FOUND_ERR) {
1406 // Leaf does not exist, it's just a suggested file name. 1476 // Leaf does not exist, it's just a suggested file name.
1407 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY); 1477 self.changeDirectoryEntry(baseDirEntry, CD_NO_HISTORY);
1408 } else { 1478 } else {
1409 console.log('Unexpected error resolving default leaf: ' + err); 1479 console.log('Unexpected error resolving default leaf: ' + err);
1410 self.changeDirectoryEntry('/', CD_NO_HISTORY); 1480 self.changeDirectoryEntry('/', CD_NO_HISTORY);
1411 } 1481 }
1412 } 1482 }
1413 1483
1414 self.resolvePath(path, onLeafFound, onLeafError); 1484 self.resolvePath(path, onLeafFound, onLeafError);
1415 } 1485 }
1416 1486
1417 function onBaseError(err) { 1487 function onBaseError(err) {
1418 // Set filename first so OK button will update in changeDirectory. 1488 // Set filename first so OK button will update in changeDirectory.
1419 self.filenameInput_.value = leafName; 1489 self.filenameInput_.value = leafName;
1490 self.selectDefaultPathInFilenameInput_();
1420 console.log('Unexpected error resolving default base "' + 1491 console.log('Unexpected error resolving default base "' +
1421 baseName + '": ' + err); 1492 baseName + '": ' + err);
1422 self.changeDirectory('/', CD_NO_HISTORY); 1493 self.changeDirectory('/', CD_NO_HISTORY);
1423 } 1494 }
1424 1495
1425 if (baseName) { 1496 if (baseName) {
1426 this.filesystem_.root.getDirectory( 1497 this.filesystem_.root.getDirectory(
1427 baseName, {create: false}, onBaseFound, onBaseError); 1498 baseName, {create: false}, onBaseFound, onBaseError);
1428 } else { 1499 } else {
1429 onBaseFound(this.filesystem_.root); 1500 onBaseFound(this.filesystem_.root);
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
1673 1744
1674 var icon = this.document_.createElement('div'); 1745 var icon = this.document_.createElement('div');
1675 icon.className = 'detail-icon'; 1746 icon.className = 'detail-icon';
1676 this.getIconType(entry); 1747 this.getIconType(entry);
1677 icon.setAttribute('iconType', entry.cachedIconType_); 1748 icon.setAttribute('iconType', entry.cachedIconType_);
1678 div.appendChild(icon); 1749 div.appendChild(icon);
1679 1750
1680 return div; 1751 return div;
1681 }; 1752 };
1682 1753
1683 FileManager.prototype.getLabelForRootPath_ = function(path) { 1754 FileManager.prototype.getLabelForRootPath_ = function(path) {
SeRya 2011/11/28 10:30:55 Looks like meaning of the parameter has changed. N
dgozman 2011/11/28 11:45:53 Done.
1684 // This hack lets us localize the top level directories. 1755 // This hack lets us localize the top level directories.
1685 if (path == 'Downloads') 1756 if (path == DOWNLOADS_DIRECTORY)
1686 return str('DOWNLOADS_DIRECTORY_LABEL'); 1757 return str('CHROMEBOOK_DIRECTORY_LABEL');
1687 1758
1688 if (path == 'archive') 1759 if (path == ARCHIVE_DIRECTORY)
1689 return str('ARCHIVE_DIRECTORY_LABEL'); 1760 return str('ARCHIVE_DIRECTORY_LABEL');
1761 if (isParentPath(ARCHIVE_DIRECTORY, path))
1762 return path.substring(ARCHIVE_DIRECTORY.length + 1);
1690 1763
1691 if (path == 'removable') 1764 if (path == REMOVABLE_DIRECTORY)
1692 return str('REMOVABLE_DIRECTORY_LABEL'); 1765 return str('REMOVABLE_DIRECTORY_LABEL');
1766 if (isParentPath(REMOVABLE_DIRECTORY, path))
1767 return path.substring(REMOVABLE_DIRECTORY.length + 1);
1693 1768
1694 return path || str('ROOT_DIRECTORY_LABEL'); 1769 return path || str('ROOT_DIRECTORY_LABEL');
SeRya 2011/11/28 10:30:55 path == '/', right?
dgozman 2011/11/28 11:45:53 Path may be arbitrary here. Changed to remove |pat
1695 }; 1770 };
1696 1771
1772 FileManager.prototype.getRootIconUrl_ = function(path, opt_small) {
1773 var iconUrl = opt_small ? 'images/chromebook_28x28.png' :
1774 'images/chromebook_24x24.png';
1775 if (isParentPath(REMOVABLE_DIRECTORY, path))
1776 iconUrl = 'images/filetype_device.png';
1777 if (isParentPath(ARCHIVE_DIRECTORY, path))
1778 iconUrl = 'images/icon_mount_archive_16x16.png';
1779 return chrome.extension.getURL(iconUrl);
1780 };
1781
1782 FileManager.prototype.renderRoot_ = function(entry) {
1783 var li = this.document_.createElement('li');
1784 li.className = 'root-item';
1785
1786 var icon = this.document_.createElement('img');
1787 icon.setAttribute('src', this.getRootIconUrl_(entry.fullPath, false));
1788 li.appendChild(icon);
1789
1790 var div = this.document_.createElement('div');
1791 div.textContent = this.getLabelForRootPath_(entry.fullPath);
1792 li.appendChild(div);
1793
1794 if (isParentPath(REMOVABLE_DIRECTORY, entry.fullPath) ||
1795 isParentPath(ARCHIVE_DIRECTORY, entry.fullPath)) {
1796 var spacer = this.document_.createElement('div');
1797 spacer.className = 'spacer';
1798 li.appendChild(spacer);
1799
1800 var eject = this.document_.createElement('img');
1801 eject.className = 'root-eject';
1802 eject.setAttribute('src', chrome.extension.getURL('images/eject.png'));
1803 eject.addEventListener('click', this.onEjectClick_.bind(this, entry));
1804 li.appendChild(eject);
1805 }
1806
1807 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR);
1808 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR);
1809 return li;
1810 };
1811
1812 /**
1813 * Handler for eject button clicked.
1814 * @param {Entry} entry Entry to eject.
1815 * @param {Event} event The event.
1816 */
1817 FileManager.prototype.onEjectClick_ = function(entry, event) {
1818 this.unmountRequests_.push(entry.toURL());
1819 chrome.fileBrowserPrivate.removeMount(entry.fullPath);
1820 };
1821
1697 /** 1822 /**
1698 * Render the Name column of the detail table. 1823 * Render the Name column of the detail table.
1699 * 1824 *
1700 * Invoked by cr.ui.Table when a file needs to be rendered. 1825 * Invoked by cr.ui.Table when a file needs to be rendered.
1701 * 1826 *
1702 * @param {Entry} entry The Entry object to render. 1827 * @param {Entry} entry The Entry object to render.
1703 * @param {string} columnId The id of the column to be rendered. 1828 * @param {string} columnId The id of the column to be rendered.
1704 * @param {cr.ui.Table} table The table doing the rendering. 1829 * @param {cr.ui.Table} table The table doing the rendering.
1705 */ 1830 */
1706 FileManager.prototype.renderName_ = function(entry, columnId, table) { 1831 FileManager.prototype.renderName_ = function(entry, columnId, table) {
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
2035 // Skip the button creation. 2160 // Skip the button creation.
2036 if (!str('ENABLE_PHOTO_EDITOR')) continue; 2161 if (!str('ENABLE_PHOTO_EDITOR')) continue;
2037 this.galleryTask_ = task; 2162 this.galleryTask_ = task;
2038 } 2163 }
2039 } 2164 }
2040 this.renderTaskButton_(task); 2165 this.renderTaskButton_(task);
2041 } 2166 }
2042 2167
2043 // These are done in separate functions, as the checks require 2168 // These are done in separate functions, as the checks require
2044 // asynchronous function calls. 2169 // asynchronous function calls.
2045 this.maybeRenderUnmountTask_(selection);
2046 this.maybeRenderFormattingTask_(selection); 2170 this.maybeRenderFormattingTask_(selection);
2047 }; 2171 };
2048 2172
2049 FileManager.prototype.renderTaskButton_ = function(task) { 2173 FileManager.prototype.renderTaskButton_ = function(task) {
2050 var button = this.document_.createElement('button'); 2174 var button = this.document_.createElement('button');
2051 button.addEventListener('click', 2175 button.addEventListener('click',
2052 this.onTaskButtonClicked_.bind(this, task)); 2176 this.onTaskButtonClicked_.bind(this, task));
2053 button.className = 'task-button'; 2177 button.className = 'task-button';
2054 2178
2055 var img = this.document_.createElement('img'); 2179 var img = this.document_.createElement('img');
2056 img.src = task.iconUrl; 2180 img.src = task.iconUrl;
2057 2181
2058 button.appendChild(img); 2182 button.appendChild(img);
2059 var label = this.document_.createElement('div'); 2183 var label = this.document_.createElement('div');
2060 label.appendChild(this.document_.createTextNode(task.title)) 2184 label.appendChild(this.document_.createTextNode(task.title))
2061 button.appendChild(label); 2185 button.appendChild(label);
2062 2186
2063 this.taskButtons_.appendChild(button); 2187 this.taskButtons_.appendChild(button);
2064 }; 2188 };
2065 2189
2066 /** 2190 /**
2067 * Checks whether unmount task should be displayed and if the answer is
2068 * affirmative renders it.
2069 * @param {Object} selection Selected files object.
2070 */
2071 FileManager.prototype.maybeRenderUnmountTask_ = function(selection) {
2072 for (var index = 0; index < selection.urls.length; ++index) {
2073 // Each url should be a mount point.
2074 var path = selection.entries[index].fullPath;
2075 var found = false;
2076 for (var i = 0; i < this.mountPoints_.length; i++) {
2077 var mountPath = this.mountPoints_[i].mountPath;
2078 if (mountPath[0] != '/') {
2079 mountPath = '/' + mountPath;
2080 }
2081 if (mountPath == path && this.mountPoints_[i].mountType == 'file') {
2082 found = true;
2083 break;
2084 }
2085 }
2086 if (!found)
2087 return;
2088 }
2089 this.renderTaskButton_({
2090 taskId: this.getExtensionId_() + '|unmount-archive',
2091 iconUrl:
2092 chrome.extension.getURL('images/icon_unmount_archive_16x16.png'),
2093 title: str('UNMOUNT_ARCHIVE'),
2094 internal: true
2095 });
2096 };
2097
2098 /**
2099 * Checks whether formatting task should be displayed and if the answer is 2191 * Checks whether formatting task should be displayed and if the answer is
2100 * affirmative renders it. Includes asynchronous calls, so it's splitted into 2192 * affirmative renders it. Includes asynchronous calls, so it's splitted into
2101 * three parts. 2193 * three parts.
2102 * @param {Object} selection Selected files object. 2194 * @param {Object} selection Selected files object.
2103 */ 2195 */
2104 FileManager.prototype.maybeRenderFormattingTask_ = function(selection) { 2196 FileManager.prototype.maybeRenderFormattingTask_ = function(selection) {
2105 // Not to make unnecessary getMountPoints() call we doublecheck if there is 2197 // Not to make unnecessary getMountPoints() call we doublecheck if there is
2106 // only one selected entry. 2198 // only one selected entry.
2107 if (selection.entries.length != 1) 2199 if (selection.entries.length != 1)
2108 return; 2200 return;
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
2169 chrome.fileBrowserPrivate.executeTask(task.taskId, urls); 2261 chrome.fileBrowserPrivate.executeTask(task.taskId, urls);
2170 }; 2262 };
2171 2263
2172 /** 2264 /**
2173 * Event handler called when some volume was mounted or unmouted. 2265 * Event handler called when some volume was mounted or unmouted.
2174 */ 2266 */
2175 FileManager.prototype.onMountCompleted_ = function(event) { 2267 FileManager.prototype.onMountCompleted_ = function(event) {
2176 var self = this; 2268 var self = this;
2177 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { 2269 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) {
2178 self.mountPoints_ = mountPoints; 2270 self.mountPoints_ = mountPoints;
2271 var changeDirectoryTo = null;
2272
2179 if (event.eventType == 'mount') { 2273 if (event.eventType == 'mount') {
2180 for (var index = 0; index < self.mountRequests_.length; ++index) { 2274 // Mount request finished - remove it.
2181 if (self.mountRequests_[index] == event.sourceUrl) { 2275 var index = self.mountRequests_.indexOf(event.sourceUrl);
2182 self.mountRequests_.splice(index, 1); 2276 if (index != -1) {
2183 if (event.status == 'success') { 2277 self.mountRequests_.splice(index, 1);
2184 self.changeDirectory(event.mountPath); 2278 // Go to mounted directory, if request was initiated from this tab.
2185 } else { 2279 if (event.status == 'success')
2186 // Report mount error. 2280 changeDirectoryTo = event.mountPath;
2187 if (event.mountType == 'file') {
2188 var fileName = event.sourceUrl.substr(
2189 event.sourceUrl.lastIndexOf('/') + 1);
2190 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName,
2191 event.status));
2192 }
2193 }
2194 return;
2195 }
2196 } 2281 }
2197 } 2282 }
2198 2283
2284 if (event.eventType == 'unmount') {
2285 // Unmount request finished - remove it.
2286 var index = self.unmountRequests_.indexOf(event.sourceUrl);
2287 if (index != -1)
2288 self.unmountRequests_.splice(index, 1);
2289 }
2290
2291 if (event.eventType == 'mount' && event.status != 'success' &&
2292 event.mountType == 'file') {
2293 // Report mount error.
2294 var fileName = event.sourceUrl.substr(
2295 event.sourceUrl.lastIndexOf('/') + 1);
2296 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', fileName,
2297 event.status));
2298 }
2299
2300 if (event.eventType == 'unmount' && event.status != 'success') {
2301 // Report unmount error.
2302 // TODO(dgozman): introduce string and show alert here.
2303 }
2304
2199 if (event.eventType == 'unmount' && event.status == 'success' && 2305 if (event.eventType == 'unmount' && event.status == 'success' &&
2200 self.currentDirEntry_ && 2306 self.currentDirEntry_ &&
2201 isParentPath(event.mountPath, self.currentDirEntry_.fullPath)) { 2307 isParentPath(event.mountPath, self.currentDirEntry_.fullPath)) {
2202 self.changeDirectory(getParentPath(event.mountPath)); 2308 changeDirectoryTo = getParentPath(event.mountPath);
2203 return;
2204 } 2309 }
2205 2310
2206 var rescanDirectoryNeeded = (event.status == 'success'); 2311 // In the case of success, roots are changed and should be rescanned.
2207 for (var i = 0; i < mountPoints.length; i++) { 2312 if (event.status == 'success')
2208 if (event.sourceUrl == mountPoints[i].sourceUrl && 2313 self.updateRoots_(changeDirectoryTo);
2209 mountPoints[i].mountCondition != '') {
2210 rescanDirectoryNeeded = true;
2211 }
2212 }
2213 // TODO(dgozman): rescan directory, only if it contains mounted points,
2214 // when mounts location will be decided.
2215 if (rescanDirectoryNeeded)
2216 self.rescanDirectory_(null, 300);
2217 }); 2314 });
2218 }; 2315 };
2219 2316
2220 /** 2317 /**
2221 * Event handler called when some internal task should be executed. 2318 * Event handler called when some internal task should be executed.
2222 */ 2319 */
2223 FileManager.prototype.onFileTaskExecute_ = function(id, details) { 2320 FileManager.prototype.onFileTaskExecute_ = function(id, details) {
2224 var urls = details.urls; 2321 var urls = details.urls;
2225 if (id == 'preview') { 2322 if (id == 'preview') {
2226 g_slideshow_data = urls; 2323 g_slideshow_data = urls;
2227 chrome.tabs.create({url: "slideshow.html"}); 2324 chrome.tabs.create({url: "slideshow.html"});
2228 } else if (id == 'play' || id == 'enqueue') { 2325 } else if (id == 'play' || id == 'enqueue') {
2229 chrome.fileBrowserPrivate.viewFiles(urls, id); 2326 chrome.fileBrowserPrivate.viewFiles(urls, id);
2230 } else if (id == 'mount-archive') { 2327 } else if (id == 'mount-archive') {
2231 for (var index = 0; index < urls.length; ++index) { 2328 for (var index = 0; index < urls.length; ++index) {
2232 this.mountRequests_.push(urls[index]); 2329 this.mountRequests_.push(urls[index]);
2233 chrome.fileBrowserPrivate.addMount(urls[index], 'file', {}); 2330 chrome.fileBrowserPrivate.addMount(urls[index], 'file', {});
2234 } 2331 }
2235 } else if (id == 'unmount-archive') {
2236 for (var index = 0; index < urls.length; ++index) {
2237 chrome.fileBrowserPrivate.removeMount(urls[index]);
2238 }
2239 } else if (id == 'format-device') { 2332 } else if (id == 'format-device') {
2240 this.confirm.show(str('FORMATTING_WARNING'), function() { 2333 this.confirm.show(str('FORMATTING_WARNING'), function() {
2241 chrome.fileBrowserPrivate.formatDevice(urls[0]); 2334 chrome.fileBrowserPrivate.formatDevice(urls[0]);
2242 }); 2335 });
2243 } else if (id == 'gallery') { 2336 } else if (id == 'gallery') {
2244 // Pass to gallery all possible tasks except the gallery itself. 2337 // Pass to gallery all possible tasks except the gallery itself.
2245 var noGallery = []; 2338 var noGallery = [];
2246 for (var index = 0; index < details.task.allTasks.length; index++) { 2339 for (var index = 0; index < details.task.allTasks.length; index++) {
2247 var task = details.task.allTasks[index]; 2340 var task = details.task.allTasks[index];
2248 if (task.taskId != this.getExtensionId_() + '|gallery') { 2341 if (task.taskId != this.getExtensionId_() + '|gallery') {
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
2305 self.metadataProvider_, 2398 self.metadataProvider_,
2306 shareActions, 2399 shareActions,
2307 str); 2400 str);
2308 }; 2401 };
2309 2402
2310 galleryFrame.src = 'js/image_editor/gallery.html'; 2403 galleryFrame.src = 'js/image_editor/gallery.html';
2311 this.dialogDom_.appendChild(galleryFrame); 2404 this.dialogDom_.appendChild(galleryFrame);
2312 galleryFrame.focus(); 2405 galleryFrame.focus();
2313 }; 2406 };
2314 2407
2408 FileManager.prototype.getRootForPath_ = function(path) {
2409 for (var index = 0; index < this.rootEntries_.length; index++) {
2410 if (isParentPath(this.rootEntries_[index].fullPath, path)) {
2411 return index;
2412 }
2413 }
2414 return -1;
2415 };
2416
2315 /** 2417 /**
2316 * Update the breadcrumb display to reflect the current directory. 2418 * Update the breadcrumb display to reflect the current directory.
2317 */ 2419 */
2318 FileManager.prototype.updateBreadcrumbs_ = function() { 2420 FileManager.prototype.updateBreadcrumbs_ = function() {
2319 var bc = this.dialogDom_.querySelector('.breadcrumbs'); 2421 var bc = this.dialogDom_.querySelector('.breadcrumbs');
2320 bc.innerHTML = ''; 2422 bc.innerHTML = '';
2321 2423
2322 var fullPath = this.currentDirEntry_.fullPath.replace(/\/$/, ''); 2424 var fullPath = this.currentDirEntry_.fullPath;
2323 var pathNames = fullPath.split('/'); 2425 var rootIndex = this.getRootForPath_(fullPath);
2324 var path = ''; 2426 if (rootIndex == -1) {
2427 console.error('Not root for: ' + fullPath);
2428 return;
2429 }
2430 var root = this.rootEntries_[rootIndex];
2431
2432 var icon = this.document_.createElement('img');
2433 icon.className = 'breadcrumb-icon';
2434 icon.setAttribute('src', this.getRootIconUrl_(root.fullPath, true));
2435 bc.appendChild(icon);
2436
2437 var rootPath = root.fullPath;
2438 var relativePath = fullPath.substring(rootPath.length);
2439 var pathNames = relativePath.replace(/\/$/, '').split('/');
2440 if (pathNames[0] == '')
2441 pathNames.splice(0, 1);
2442
2443 // We need a first breadcrumb for root, so placing last name from
2444 // rootPath as first name of relativePath.
2445 var rootPathNames = rootPath.replace(/\/$/, '').split('/');
2446 pathNames.splice(0, 0, rootPathNames[rootPathNames.length - 1]);
2447 rootPathNames.splice(rootPathNames.length - 1, 1);
2448 var path = rootPathNames.join('/') + '/';
2325 2449
2326 for (var i = 0; i < pathNames.length; i++) { 2450 for (var i = 0; i < pathNames.length; i++) {
2327 var pathName = pathNames[i]; 2451 var pathName = pathNames[i];
2328 path += pathName + '/'; 2452 path += pathName;
2329 2453
2330 var div = this.document_.createElement('div'); 2454 var div = this.document_.createElement('div');
2331 div.className = 'breadcrumb-path'; 2455 div.className = 'breadcrumb-path';
2332 if (i <= 1) { 2456 if (i == 0) {
2333 // i == 0: root directory itself, i == 1: the files it contains. 2457 div.textContent = this.getLabelForRootPath_(path);
SeRya 2011/11/28 10:30:55 Remove braces.
dgozman 2011/11/28 11:45:53 Done.
2334 div.textContent = this.getLabelForRootPath_(pathName);
2335 } else { 2458 } else {
2336 div.textContent = pathName; 2459 div.textContent = pathName;
2337 } 2460 }
2338 2461
2462 path = path + '/';
2339 div.path = path; 2463 div.path = path;
2340 div.addEventListener('click', this.onBreadcrumbClick_.bind(this)); 2464 div.addEventListener('click', this.onBreadcrumbClick_.bind(this));
2341 2465
2342 bc.appendChild(div); 2466 bc.appendChild(div);
2343 2467
2344 if (i == pathNames.length - 1) { 2468 if (i == pathNames.length - 1) {
2345 div.classList.add('breadcrumb-last'); 2469 div.classList.add('breadcrumb-last');
2346 } else { 2470 } else {
2347 var spacer = this.document_.createElement('div'); 2471 var spacer = this.document_.createElement('div');
2348 spacer.className = 'breadcrumb-spacer'; 2472 spacer.className = 'breadcrumb-spacer';
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
2428 for (var i = 0; i < this.dataModel_.length; i++) { 2552 for (var i = 0; i < this.dataModel_.length; i++) {
2429 if (this.dataModel_.item(i).name == name) { 2553 if (this.dataModel_.item(i).name == name) {
2430 this.currentList_.selectionModel.selectedIndex = i; 2554 this.currentList_.selectionModel.selectedIndex = i;
2431 this.currentList_.scrollIndexIntoView(i); 2555 this.currentList_.scrollIndexIntoView(i);
2432 this.currentList_.focus(); 2556 this.currentList_.focus();
2433 return; 2557 return;
2434 } 2558 }
2435 } 2559 }
2436 }; 2560 };
2437 2561
2562 FileManager.prototype.updateRootsListSelection_ = function() {
2563 if (!this.currentDirEntry_) return;
2564 var index = this.getRootForPath_(this.currentDirEntry_.fullPath);
2565 if (index == -1) {
2566 this.rootsList_.selectionModel.selectedIndex = 0;
2567 } else {
2568 if (this.rootsList_.selectionModel.selectedIndex != index)
2569 this.rootsList_.selectionModel.selectedIndex = index;
2570 }
2571 };
2572
2438 /** 2573 /**
2439 * Add the file/directory with given name to the current selection. 2574 * Add the file/directory with given name to the current selection.
2440 * 2575 *
2441 * @param {string} name The name of the entry to select. 2576 * @param {string} name The name of the entry to select.
2442 * @return {boolean} Whether entry exists. 2577 * @return {boolean} Whether entry exists.
2443 */ 2578 */
2444 FileManager.prototype.addItemToSelection = function(name) { 2579 FileManager.prototype.addItemToSelection = function(name) {
2445 var entryExists = false; 2580 var entryExists = false;
2446 for (var i = 0; i < this.dataModel_.length; i++) { 2581 for (var i = 0; i < this.dataModel_.length; i++) {
2447 if (this.dataModel_.item(i).name == name) { 2582 if (this.dataModel_.item(i).name == name) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
2543 FileManager.prototype.changeDirectoryEntry = function(dirEntry, 2678 FileManager.prototype.changeDirectoryEntry = function(dirEntry,
2544 opt_saveHistory, 2679 opt_saveHistory,
2545 opt_selectedEntry, 2680 opt_selectedEntry,
2546 opt_callback) { 2681 opt_callback) {
2547 if (typeof opt_saveHistory == 'undefined') { 2682 if (typeof opt_saveHistory == 'undefined') {
2548 opt_saveHistory = true; 2683 opt_saveHistory = true;
2549 } else { 2684 } else {
2550 opt_saveHistory = !!opt_saveHistory; 2685 opt_saveHistory = !!opt_saveHistory;
2551 } 2686 }
2552 2687
2553 var location = '#' + encodeURI(dirEntry.fullPath); 2688 // Some directories are above roots, so we instead show the first root.
2689 // There may be request to change directory above the roots. For example,
2690 // when usb-dirve is removed, we try to change to the parent directory,
2691 // which is REMOVABLE_DIRECTORY.
2692 if (!dirEntry || dirEntry.fullPath == '/' ||
2693 dirEntry.fullPath == REMOVABLE_DIRECTORY ||
2694 dirEntry.fullPath == ARCHIVE_DIRECTORY) {
2695 dirEntry = this.rootEntries_[0] || dirEntry;
2696 }
2697
2698 /* var location = '#' + encodeURI(dirEntry.fullPath);
SeRya 2011/11/28 10:30:55 Uncomment.
dgozman 2011/11/28 11:45:53 Done.
2554 if (opt_saveHistory) { 2699 if (opt_saveHistory) {
2555 history.pushState(undefined, dirEntry.fullPath, location); 2700 history.pushState(undefined, dirEntry.fullPath, location);
2556 } else if (window.location.hash != location) { 2701 } else if (window.location.hash != location) {
2557 // If the user typed URL manually that is not canonical it would be fixed 2702 // If the user typed URL manually that is not canonical it would be fixed
2558 // here. However it seems history.replaceState doesn't work properly 2703 // here. However it seems history.replaceState doesn't work properly
2559 // with rewritable URLs (while does with history.pushState). It changes 2704 // with rewritable URLs (while does with history.pushState). It changes
2560 // window.location but doesn't change content of the ombibox. 2705 // window.location but doesn't change content of the ombibox.
2561 history.replaceState(undefined, dirEntry.fullPath, location); 2706 history.replaceState(undefined, dirEntry.fullPath, location);
2562 } 2707 }
2563 2708 */
2564 if (this.currentDirEntry_ && 2709 if (this.currentDirEntry_ &&
2565 this.currentDirEntry_.fullPath == dirEntry.fullPath) { 2710 this.currentDirEntry_.fullPath == dirEntry.fullPath) {
2566 // Directory didn't actually change. 2711 // Directory didn't actually change.
2567 if (opt_selectedEntry) 2712 if (opt_selectedEntry)
2568 this.selectEntry(opt_selectedEntry); 2713 this.selectEntry(opt_selectedEntry);
2569 return; 2714 return;
2570 } 2715 }
2571 2716
2572 var e = new cr.Event('directory-changed'); 2717 var e = new cr.Event('directory-changed');
2573 e.previousDirEntry = this.currentDirEntry_; 2718 e.previousDirEntry = this.currentDirEntry_;
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
2779 // then the default action of this click event fires and toggles the 2924 // then the default action of this click event fires and toggles the
2780 // checkbox back off. 2925 // checkbox back off.
2781 // 2926 //
2782 // Since we're going to force checkboxes into the correct state for any 2927 // Since we're going to force checkboxes into the correct state for any
2783 // multi-selection, we can prevent this shift click from toggling the 2928 // multi-selection, we can prevent this shift click from toggling the
2784 // checkbox and avoid the trouble. 2929 // checkbox and avoid the trouble.
2785 event.preventDefault(); 2930 event.preventDefault();
2786 } 2931 }
2787 }; 2932 };
2788 2933
2934 FileManager.prototype.onRootsSelectionChanged_ = function(event) {
2935 var root = this.rootEntries_[this.rootsList_.selectionModel.selectedIndex];
2936 this.changeDirectoryEntry(root);
2937 };
2938
2939 FileManager.prototype.selectDefaultPathInFilenameInput_ = function() {
2940 var input = this.filenameInput_;
2941 input.focus();
2942 var selectionEnd = input.value.lastIndexOf('.');
2943 if (selectionEnd == -1) {
2944 input.select();
2945 } else {
2946 input.selectionStart = 0;
2947 input.selectionEnd = selectionEnd;
2948 }
2949 // Clear, so we never do this again.
2950 this.params_.defaultPath = '';
2951 };
2952
2789 /** 2953 /**
2790 * Update the UI when the selection model changes. 2954 * Update the UI when the selection model changes.
2791 * 2955 *
2792 * @param {cr.Event} event The change event. 2956 * @param {cr.Event} event The change event.
2793 */ 2957 */
2794 FileManager.prototype.onSelectionChanged_ = function(event) { 2958 FileManager.prototype.onSelectionChanged_ = function(event) {
2795 this.summarizeSelection_(); 2959 this.summarizeSelection_();
2796 2960
2797 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { 2961 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) {
2798 // If this is a save-as dialog, copy the selected file into the filename 2962 // If this is a save-as dialog, copy the selected file into the filename
2799 // input text box. 2963 // input text box.
2800 2964
2801 if (this.selection && 2965 if (this.selection &&
2802 this.selection.totalCount == 1 && 2966 this.selection.totalCount == 1 &&
2803 this.selection.entries[0].isFile) 2967 this.selection.entries[0].isFile &&
2968 this.filenameInput_.value != this.selection.entries[0].name) {
2804 this.filenameInput_.value = this.selection.entries[0].name; 2969 this.filenameInput_.value = this.selection.entries[0].name;
2970 if (this.params_.defaultPath == this.selection.entries[0].fullPath)
2971 this.selectDefaultPathInFilenameInput_();
2972 }
2805 } 2973 }
2806 2974
2807 this.updateOkButton_(); 2975 this.updateOkButton_();
2808 2976
2809 var self = this; 2977 var self = this;
2810 setTimeout(function() { self.onSelectionChangeComplete_(event) }, 0); 2978 setTimeout(function() { self.onSelectionChangeComplete_(event) }, 0);
2811 }; 2979 };
2812 2980
2813 /** 2981 /**
2814 * Handle selection change related tasks that won't run properly during 2982 * Handle selection change related tasks that won't run properly during
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
2947 * Update the UI when the current directory changes. 3115 * Update the UI when the current directory changes.
2948 * 3116 *
2949 * @param {cr.Event} event The directory-changed event. 3117 * @param {cr.Event} event The directory-changed event.
2950 */ 3118 */
2951 FileManager.prototype.onDirectoryChanged_ = function(event) { 3119 FileManager.prototype.onDirectoryChanged_ = function(event) {
2952 this.updateCommands_(); 3120 this.updateCommands_();
2953 this.updateOkButton_(); 3121 this.updateOkButton_();
2954 3122
2955 this.checkFreeSpace_(this.currentDirEntry_.fullPath); 3123 this.checkFreeSpace_(this.currentDirEntry_.fullPath);
2956 3124
2957 // New folder should never be enabled in the root or media/ directories. 3125 // TODO(dgozman): title may be better than this.
2958 this.newFolderButton_.disabled = isSystemDirEntry(this.currentDirEntry_);
2959
2960 this.document_.title = this.currentDirEntry_.fullPath; 3126 this.document_.title = this.currentDirEntry_.fullPath;
2961 3127
2962 var self = this; 3128 var self = this;
2963 3129
2964 if (this.subscribedOnDirectoryChanges_) { 3130 if (this.subscribedOnDirectoryChanges_) {
2965 chrome.fileBrowserPrivate.removeFileWatch(event.previousDirEntry.toURL(), 3131 chrome.fileBrowserPrivate.removeFileWatch(event.previousDirEntry.toURL(),
2966 function(result) { 3132 function(result) {
2967 if (!result) { 3133 if (!result) {
2968 console.log('Failed to remove file watch'); 3134 console.log('Failed to remove file watch');
2969 } 3135 }
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
3045 // Updated when a user clicks on the label of a file, used to detect 3211 // Updated when a user clicks on the label of a file, used to detect
3046 // when a click is eligible to trigger a rename. Can be null, or 3212 // when a click is eligible to trigger a rename. Can be null, or
3047 // an object with 'path' and 'date' properties. 3213 // an object with 'path' and 'date' properties.
3048 this.lastLabelClick_ = null; 3214 this.lastLabelClick_ = null;
3049 3215
3050 // Clear the table first. 3216 // Clear the table first.
3051 this.dataModel_.splice(0, this.dataModel_.length); 3217 this.dataModel_.splice(0, this.dataModel_.length);
3052 this.currentList_.selectionModel.clear(); 3218 this.currentList_.selectionModel.clear();
3053 3219
3054 this.updateBreadcrumbs_(); 3220 this.updateBreadcrumbs_();
3221 this.updateRootsListSelection_();
3055 3222
3056 if (this.currentDirEntry_.fullPath != '/') { 3223 // Add current request to pending result list
3057 // Add current request to pending result list 3224 this.pendingRescanQueue_.push({
3058 this.pendingRescanQueue_.push({ 3225 onSuccess:opt_callback,
3059 onSuccess:opt_callback, 3226 onError:opt_onError
3060 onError:opt_onError 3227 });
3061 });
3062 3228
3063 if (this.rescanRunning_) 3229 if (this.rescanRunning_)
3064 return; 3230 return;
3065 3231
3066 this.rescanRunning_ = true; 3232 this.rescanRunning_ = true;
3067 3233
3068 // The current list of callbacks is saved and reset. Subsequent 3234 // The current list of callbacks is saved and reset. Subsequent
3069 // calls to rescanDirectory_ while we're still pending will be 3235 // calls to rescanDirectory_ while we're still pending will be
3070 // saved and will cause an additional rescan to happen after a delay. 3236 // saved and will cause an additional rescan to happen after a delay.
3071 var callbacks = this.pendingRescanQueue_; 3237 var callbacks = this.pendingRescanQueue_;
3072 3238
3073 this.pendingRescanQueue_ = []; 3239 this.pendingRescanQueue_ = [];
3074 3240
3075 var self = this; 3241 var self = this;
3076 var reader; 3242 var reader;
3077 3243
3078 function onError() { 3244 function onError() {
3245 if (self.pendingRescanQueue_.length > 0) {
3246 setTimeout(self.rescanDirectory_.bind(self),
3247 SIMULTANEOUS_RESCAN_INTERVAL);
3248 }
3249
3250 self.rescanRunning_ = false;
3251
3252 for (var i= 0; i < callbacks.length; i++) {
3253 if (callbacks[i].onError)
3254 try {
3255 callbacks[i].onError();
3256 } catch (ex) {
3257 console.error('Caught exception while notifying about error: ' +
3258 name, ex);
3259 }
3260 }
3261 }
3262
3263 function onReadSome(entries) {
3264 if (entries.length == 0) {
3265 metrics.recordTime('DirectoryScan');
3266 if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) {
3267 metrics.reportCount("DownloadsCount", self.dataModel_.length);
3268 }
3269
3079 if (self.pendingRescanQueue_.length > 0) { 3270 if (self.pendingRescanQueue_.length > 0) {
3080 setTimeout(self.rescanDirectory_.bind(self), 3271 setTimeout(self.rescanDirectory_.bind(self),
3081 SIMULTANEOUS_RESCAN_INTERVAL); 3272 SIMULTANEOUS_RESCAN_INTERVAL);
3082 } 3273 }
3083 3274
3084 self.rescanRunning_ = false; 3275 self.rescanRunning_ = false;
3085
3086 for (var i= 0; i < callbacks.length; i++) { 3276 for (var i= 0; i < callbacks.length; i++) {
3087 if (callbacks[i].onError) 3277 if (callbacks[i].onSuccess)
3088 try { 3278 try {
3089 callbacks[i].onError(); 3279 callbacks[i].onSuccess();
3090 } catch (ex) { 3280 } catch (ex) {
3091 console.error('Caught exception while notifying about error: ' + 3281 console.error('Caught exception while notifying about error: ' +
3092 name, ex); 3282 name, ex);
3093 } 3283 }
3094 } 3284 }
3285
3286 return;
3095 } 3287 }
3096 3288
3097 function onReadSome(entries) { 3289 // Splice takes the to-be-spliced-in array as individual parameters,
3098 if (entries.length == 0) { 3290 // rather than as an array, so we need to perform some acrobatics...
3099 metrics.recordTime('DirectoryScan'); 3291 var spliceArgs = [].slice.call(entries);
3100 if (self.currentDirEntry_.fullPath == DOWNLOADS_DIRECTORY) {
3101 metrics.reportCount("DownloadsCount", self.dataModel_.length);
3102 }
3103 3292
3104 if (self.pendingRescanQueue_.length > 0) { 3293 // Hide files that start with a dot ('.').
3105 setTimeout(self.rescanDirectory_.bind(self), 3294 // TODO(rginda): User should be able to override this. Support for other
3106 SIMULTANEOUS_RESCAN_INTERVAL); 3295 // commonly hidden patterns might be nice too.
3107 } 3296 if (self.filterFiles_) {
3297 spliceArgs = spliceArgs.filter(function(e) {
3298 return e.name.substr(0, 1) != '.';
3299 });
3300 }
3108 3301
3109 self.rescanRunning_ = false; 3302 spliceArgs.unshift(0, 0); // index, deleteCount
3110 for (var i= 0; i < callbacks.length; i++) { 3303 self.dataModel_.splice.apply(self.dataModel_, spliceArgs);
3111 if (callbacks[i].onSuccess)
3112 try {
3113 callbacks[i].onSuccess();
3114 } catch (ex) {
3115 console.error('Caught exception while notifying about error: ' +
3116 name, ex);
3117 }
3118 }
3119 3304
3120 return; 3305 // Keep reading until entries.length is 0.
3121 } 3306 reader.readEntries(onReadSome, onError);
3307 };
3122 3308
3123 // Splice takes the to-be-spliced-in array as individual parameters, 3309 metrics.startInterval('DirectoryScan');
3124 // rather than as an array, so we need to perform some acrobatics...
3125 var spliceArgs = [].slice.call(entries);
3126 3310
3127 // Hide files that start with a dot ('.'). 3311 // If not the root directory, just read the contents.
3128 // TODO(rginda): User should be able to override this. Support for other 3312 reader = this.currentDirEntry_.createReader();
3129 // commonly hidden patterns might be nice too. 3313 reader.readEntries(onReadSome, onError);
3130 if (self.filterFiles_) {
3131 spliceArgs = spliceArgs.filter(function(e) {
3132 return e.name.substr(0, 1) != '.';
3133 });
3134 }
3135
3136 spliceArgs.unshift(0, 0); // index, deleteCount
3137 self.dataModel_.splice.apply(self.dataModel_, spliceArgs);
3138
3139 metrics.startInterval('DirectoryScan');
3140
3141 // Keep reading until entries.length is 0.
3142 reader.readEntries(onReadSome, onError);
3143 };
3144
3145 // If not the root directory, just read the contents.
3146 reader = this.currentDirEntry_.createReader();
3147 reader.readEntries(onReadSome, onError);
3148 return;
3149 }
3150
3151 // Otherwise, use the provided list of root subdirectories, since the
3152 // real local filesystem root directory (the one we use outside the
3153 // harness) can't be enumerated yet.
3154 var spliceArgs = [].slice.call(this.rootEntries_);
3155 spliceArgs.unshift(0, 0); // index, deleteCount
3156 this.dataModel_.splice.apply(this.dataModel_, spliceArgs);
3157
3158 if (opt_callback)
3159 opt_callback();
3160 }; 3314 };
3161 3315
3162 FileManager.prototype.findListItem_ = function(event) { 3316 FileManager.prototype.findListItem_ = function(event) {
3163 var node = event.srcElement; 3317 var node = event.srcElement;
3164 while (node) { 3318 while (node) {
3165 if (node.tagName == 'LI') 3319 if (node.tagName == 'LI')
3166 break; 3320 break;
3167 node = node.parentNode; 3321 node = node.parentNode;
3168 } 3322 }
3169 3323
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
3393 var selectionEnd = input.value.lastIndexOf('.'); 3547 var selectionEnd = input.value.lastIndexOf('.');
3394 if (selectionEnd == -1) { 3548 if (selectionEnd == -1) {
3395 input.select(); 3549 input.select();
3396 } else { 3550 } else {
3397 input.selectionStart = 0; 3551 input.selectionStart = 0;
3398 input.selectionEnd = selectionEnd; 3552 input.selectionEnd = selectionEnd;
3399 } 3553 }
3400 }, 0); 3554 }, 0);
3401 }; 3555 };
3402 3556
3403 FileManager.prototype.onNewFolderButtonClick_ = function(event) { 3557 FileManager.prototype.onToggleSidebar_ = function(event) {
3558 if (this.dialogContainer_.hasAttribute('sidebar')) {
SeRya 2011/11/28 10:30:55 Now we have 3 attributes that does essentially the
dgozman 2011/11/28 11:45:53 I've filed a bug: crosbug.com/23455.
3559 this.dialogContainer_.removeAttribute('sidebar');
3560 } else {
3561 this.dialogContainer_.setAttribute('sidebar', 'sidebar');
3562 }
3563 setTimeout(this.onResize_.bind(this), 300);
3564 };
3565
3566 FileManager.prototype.onNewFolderCommand_ = function(event) {
3404 var self = this; 3567 var self = this;
3405 3568
3406 function onNameSelected(name) { 3569 function onNameSelected(name) {
3407 var valid = self.validateFileName_(name, function() { 3570 var valid = self.validateFileName_(name, function() {
3408 promptForName(name); 3571 promptForName(name);
3409 }); 3572 });
3410 3573
3411 if (!valid) { 3574 if (!valid) {
3412 // Validation failed. User will be prompted for a new name after they 3575 // Validation failed. User will be prompted for a new name after they
3413 // dismiss the validation error dialog. 3576 // dismiss the validation error dialog.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
3522 this.dialogType_ != FileManager.SELECT_FOLDER) { 3685 this.dialogType_ != FileManager.SELECT_FOLDER) {
3523 event.preventDefault(); 3686 event.preventDefault();
3524 this.onDirectoryAction(this.selection.entries[0]); 3687 this.onDirectoryAction(this.selection.entries[0]);
3525 } else if (!this.okButton_.disabled) { 3688 } else if (!this.okButton_.disabled) {
3526 event.preventDefault(); 3689 event.preventDefault();
3527 this.onOk_(); 3690 this.onOk_();
3528 } 3691 }
3529 break; 3692 break;
3530 3693
3531 case 32: // Ctrl-Space => New Folder. 3694 case 32: // Ctrl-Space => New Folder.
3532 if (this.newFolderButton_.style.display != 'none' && event.ctrlKey) { 3695 if ((this.dialogType_ == 'saveas-file' ||
3696 this.dialogType_ == 'full-page') && event.ctrlKey) {
3533 event.preventDefault(); 3697 event.preventDefault();
3534 this.onNewFolderButtonClick_(); 3698 this.onNewFolderCommand_();
3535 } 3699 }
3536 break; 3700 break;
3537 3701
3538 case 88: // Ctrl-X => Cut. 3702 case 88: // Ctrl-X => Cut.
3539 this.updateCommands_(); 3703 this.updateCommands_();
3540 if (!this.commands_['cut'].disabled) { 3704 if (!this.commands_['cut'].disabled) {
3541 event.preventDefault(); 3705 event.preventDefault();
3542 this.commands_['cut'].execute(); 3706 this.commands_['cut'].execute();
3543 } 3707 }
3544 break; 3708 break;
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after
3853 }); 4017 });
3854 }, onError); 4018 }, onError);
3855 4019
3856 function onError(err) { 4020 function onError(err) {
3857 console.log('Error while checking free space: ' + err); 4021 console.log('Error while checking free space: ' + err);
3858 setTimeout(doCheck, 1000 * 60); 4022 setTimeout(doCheck, 1000 * 60);
3859 } 4023 }
3860 } 4024 }
3861 } 4025 }
3862 })(); 4026 })();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698