Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Setting the src of an img to an empty string can crash the browser, so we | 5 // Setting the src of an img to an empty string can crash the browser, so we |
| 6 // use an empty 1x1 gif instead. | 6 // use an empty 1x1 gif instead. |
| 7 const EMPTY_IMAGE_URI = 'data:image/gif;base64,' | 7 const EMPTY_IMAGE_URI = 'data:image/gif;base64,' |
| 8 + 'R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D'; | 8 + 'R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D'; |
| 9 | 9 |
| 10 var g_slideshow_data = null; | 10 var g_slideshow_data = null; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 })(); |
| OLD | NEW |