OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 /** | 5 /** |
6 * FileManager constructor. | 6 * FileManager constructor. |
7 * | 7 * |
8 * FileManager objects encapsulate the functionality of the file selector | 8 * FileManager objects encapsulate the functionality of the file selector |
9 * dialogs, as well as the full screen file manager application (though the | 9 * dialogs, as well as the full screen file manager application (though the |
10 * latter is not yet implemented). | 10 * latter is not yet implemented). |
(...skipping 10 matching lines...) Expand all Loading... | |
21 {}; | 21 {}; |
22 | 22 |
23 this.listType_ = null; | 23 this.listType_ = null; |
24 | 24 |
25 this.selection = null; | 25 this.selection = null; |
26 | 26 |
27 this.butterTimer_ = null; | 27 this.butterTimer_ = null; |
28 this.currentButter_ = null; | 28 this.currentButter_ = null; |
29 this.butterLastShowTime_ = 0; | 29 this.butterLastShowTime_ = 0; |
30 | 30 |
31 this.watchedDirectoryUrl_ = null; | |
32 this.filesystemObserverId_ = null; | 31 this.filesystemObserverId_ = null; |
33 this.gdataObserverId_ = null; | 32 this.gdataObserverId_ = null; |
34 | 33 |
35 this.commands_ = {}; | 34 this.commands_ = {}; |
36 | 35 |
37 this.thumbnailUrlCache_ = {}; | 36 this.thumbnailUrlCache_ = {}; |
38 | 37 |
39 this.document_ = dialogDom.ownerDocument; | 38 this.document_ = dialogDom.ownerDocument; |
40 this.dialogType_ = this.params_.type || FileManager.DialogType.FULL_PAGE; | 39 this.dialogType_ = this.params_.type || FileManager.DialogType.FULL_PAGE; |
41 | 40 |
42 metrics.recordEnum('Create', this.dialogType_, | 41 metrics.recordEnum('Create', this.dialogType_, |
43 [FileManager.DialogType.SELECT_FOLDER, | 42 [FileManager.DialogType.SELECT_FOLDER, |
44 FileManager.DialogType.SELECT_SAVEAS_FILE, | 43 FileManager.DialogType.SELECT_SAVEAS_FILE, |
45 FileManager.DialogType.SELECT_OPEN_FILE, | 44 FileManager.DialogType.SELECT_OPEN_FILE, |
46 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, | 45 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, |
47 FileManager.DialogType.FULL_PAGE]); | 46 FileManager.DialogType.FULL_PAGE]); |
48 | 47 |
49 // TODO(dgozman): This will be changed to LocaleInfo. | 48 // TODO(dgozman): This will be changed to LocaleInfo. |
50 this.locale_ = new v8Locale(navigator.language); | 49 this.locale_ = new v8Locale(navigator.language); |
51 | 50 |
52 this.initFileSystem_(); | 51 this.initFileSystem_(); |
52 this.volumeManager_ = VolumeManager.getInstance(); | |
53 this.initDom_(); | 53 this.initDom_(); |
54 this.initDialogType_(); | 54 this.initDialogType_(); |
55 this.dialogDom_.style.opacity = '1'; | 55 this.dialogDom_.style.opacity = '1'; |
56 } | 56 } |
57 | 57 |
58 FileManager.prototype = { | 58 FileManager.prototype = { |
59 __proto__: cr.EventTarget.prototype | 59 __proto__: cr.EventTarget.prototype |
60 }; | 60 }; |
61 | 61 |
62 // Anonymous "namespace". | 62 // Anonymous "namespace". |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 util.UNITS = [str('SIZE_KB'), | 277 util.UNITS = [str('SIZE_KB'), |
278 str('SIZE_MB'), | 278 str('SIZE_MB'), |
279 str('SIZE_GB'), | 279 str('SIZE_GB'), |
280 str('SIZE_TB'), | 280 str('SIZE_TB'), |
281 str('SIZE_PB')]; | 281 str('SIZE_PB')]; |
282 | 282 |
283 metrics.startInterval('Load.FileSystem'); | 283 metrics.startInterval('Load.FileSystem'); |
284 | 284 |
285 var self = this; | 285 var self = this; |
286 | 286 |
287 // The list of active mount points to distinct them from other directories. | |
288 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { | |
289 self.setMountPoints_(mountPoints); | |
290 onDone(); | |
291 }); | |
292 | |
293 function onDone() { | |
294 if (self.mountPoints_ && self.filesystem_) | |
295 self.init_(); | |
296 } | |
297 | |
298 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { | 287 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { |
299 metrics.recordInterval('Load.FileSystem'); | 288 metrics.recordInterval('Load.FileSystem'); |
300 self.filesystem_ = filesystem; | 289 self.filesystem_ = filesystem; |
301 onDone(); | 290 self.init_(); |
302 }); | 291 }); |
303 }; | 292 }; |
304 | 293 |
305 FileManager.prototype.setMountPoints_ = function(mountPoints) { | |
306 this.mountPoints_ = mountPoints; | |
307 // Add gdata mount info if present. | |
308 if (this.gdataMounted_) | |
309 this.mountPoints_.push(this.gdataMountInfo_); | |
310 }; | |
311 | |
312 /** | 294 /** |
313 * Continue initializing the file manager after resolving roots. | 295 * Continue initializing the file manager after resolving roots. |
314 */ | 296 */ |
315 FileManager.prototype.init_ = function() { | 297 FileManager.prototype.init_ = function() { |
316 metrics.startInterval('Load.DOM'); | 298 metrics.startInterval('Load.DOM'); |
317 this.initCommands_(); | 299 this.initCommands_(); |
318 | 300 |
319 this.metadataCache_ = MetadataCache.createFull(); | 301 this.metadataCache_ = MetadataCache.createFull(); |
320 | 302 |
321 this.shortDateFormatter_ = | 303 this.shortDateFormatter_ = |
(...skipping 11 matching lines...) Expand all Loading... | |
333 | 315 |
334 this.table_.startBatchUpdates(); | 316 this.table_.startBatchUpdates(); |
335 this.grid_.startBatchUpdates(); | 317 this.grid_.startBatchUpdates(); |
336 | 318 |
337 this.initFileList_(); | 319 this.initFileList_(); |
338 this.initDialogs_(); | 320 this.initDialogs_(); |
339 | 321 |
340 window.addEventListener('popstate', this.onPopState_.bind(this)); | 322 window.addEventListener('popstate', this.onPopState_.bind(this)); |
341 window.addEventListener('unload', this.onUnload_.bind(this)); | 323 window.addEventListener('unload', this.onUnload_.bind(this)); |
342 | 324 |
343 this.directoryModel_.addEventListener('directory-changed', | 325 var dm = this.directoryModel_; |
326 dm.addEventListener('directory-changed', | |
344 this.onDirectoryChanged_.bind(this)); | 327 this.onDirectoryChanged_.bind(this)); |
345 var self = this; | 328 var self = this; |
346 this.directoryModel_.addEventListener('begin-update-files', function() { | 329 dm.addEventListener('begin-update-files', function() { |
347 self.currentList_.startBatchUpdates(); | 330 self.currentList_.startBatchUpdates(); |
348 }); | 331 }); |
349 this.directoryModel_.addEventListener('end-update-files', function() { | 332 dm.addEventListener('end-update-files', function() { |
350 self.restoreItemBeingRenamed_(); | 333 self.restoreItemBeingRenamed_(); |
351 self.currentList_.endBatchUpdates(); | 334 self.currentList_.endBatchUpdates(); |
352 }); | 335 }); |
353 this.directoryModel_.addEventListener('scan-started', | 336 dm.addEventListener('scan-started', this.showSpinnerLater_.bind(this)); |
354 this.showSpinnerLater_.bind(this)); | 337 dm.addEventListener('scan-completed', this.showSpinner_.bind(this, false)); |
355 this.directoryModel_.addEventListener('scan-completed', | 338 dm.addEventListener('scan-completed', |
356 this.showSpinner_.bind(this, false)); | 339 this.refreshCurrentDirectoryMetadata_.bind(this)); |
357 this.directoryModel_.addEventListener('scan-completed', | 340 dm.addEventListener('rescan-completed', |
358 this.refreshCurrentDirectoryMetadata_.bind(this)); | 341 this.refreshCurrentDirectoryMetadata_.bind(this)); |
359 this.directoryModel_.addEventListener('rescan-completed', | |
360 this.refreshCurrentDirectoryMetadata_.bind(this)); | |
361 this.addEventListener('selection-summarized', | 342 this.addEventListener('selection-summarized', |
362 this.onSelectionSummarized_.bind(this)); | 343 this.onSelectionSummarized_.bind(this)); |
363 | 344 |
364 // The list of archives requested to mount. We will show contents once | 345 this.setupCurrentDirectory_(true /* page loading */); |
365 // archive is mounted, but only for mounts from within this filebrowser tab. | |
366 this.mountRequests_ = []; | |
367 this.unmountRequests_ = []; | |
368 chrome.fileBrowserPrivate.onMountCompleted.addListener( | |
369 this.onMountCompleted_.bind(this)); | |
370 | |
371 chrome.fileBrowserPrivate.onFileChanged.addListener( | |
372 this.onFileChanged_.bind(this)); | |
373 | |
374 this.networkConnectionState_ = null; | 346 this.networkConnectionState_ = null; |
375 var queryNetworkConnectionState = function() { | 347 var queryNetworkConnectionState = function() { |
376 chrome.fileBrowserPrivate.getNetworkConnectionState( | 348 // TODO(serya): uncomment |
377 this.onNetworkConnectionChanged_.bind(this)); | 349 // chrome.fileBrowserPrivate.getNetworkConnectionState( |
350 // this.onNetworkConnectionChanged_.bind(this)); | |
378 }.bind(this); | 351 }.bind(this); |
379 queryNetworkConnectionState(); | 352 queryNetworkConnectionState(); |
380 chrome.fileBrowserPrivate.onNetworkConnectionChanged. | 353 // TODO(serya): uncomment |
381 addListener(queryNetworkConnectionState); | 354 // chrome.fileBrowserPrivate.onNetworkConnectionChanged. |
382 | 355 // addListener(queryNetworkConnectionState); |
383 var invokeHandler = !this.params_.selectOnly; | |
384 if (this.isStartingOnGData_()) { | |
385 // We are opening on a GData path. Mount GData and show | |
386 // "Loading Google Docs" message until the directory content loads. | |
387 this.dialogContainer_.setAttribute('unmounted', true); | |
388 this.initGData_(true /* dirChanged */); | |
389 // This is a one-time handler (will be nulled out on the first call). | |
390 this.setupCurrentDirectoryPostponed_ = function(event) { | |
391 this.directoryModel_.removeEventListener('directory-changed', | |
392 this.setupCurrentDirectoryPostponed_); | |
393 this.setupCurrentDirectoryPostponed_ = null; | |
394 if (event) // If called as an event handler just exit silently. | |
395 return; | |
396 this.setupCurrentDirectory_( | |
397 invokeHandler, false /* blankWhileOpeningAFile */); | |
398 }.bind(this); | |
399 this.directoryModel_.addEventListener('directory-changed', | |
400 this.setupCurrentDirectoryPostponed_); | |
401 } else { | |
402 this.setupCurrentDirectory_( | |
403 invokeHandler, true /* blankWhileOpeningAFile */); | |
404 } | |
405 | 356 |
406 this.summarizeSelection_(); | 357 this.summarizeSelection_(); |
407 | 358 |
408 var sortField = | 359 var sortField = |
409 window.localStorage['sort-field-' + this.dialogType_] || | 360 window.localStorage['sort-field-' + this.dialogType_] || |
410 'modificationTime'; | 361 'modificationTime'; |
411 var sortDirection = | 362 var sortDirection = |
412 window.localStorage['sort-direction-' + this.dialogType_] || 'desc'; | 363 window.localStorage['sort-direction-' + this.dialogType_] || 'desc'; |
413 this.directoryModel_.sortFileList(sortField, sortDirection); | 364 this.directoryModel_.sortFileList(sortField, sortDirection); |
414 | 365 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
509 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); | 460 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); |
510 this.taskItems_ = this.dialogDom_.querySelector('#tasks'); | 461 this.taskItems_ = this.dialogDom_.querySelector('#tasks'); |
511 this.okButton_ = this.dialogDom_.querySelector('.ok'); | 462 this.okButton_ = this.dialogDom_.querySelector('.ok'); |
512 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); | 463 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); |
513 this.deleteButton_ = this.dialogDom_.querySelector('#delete-button'); | 464 this.deleteButton_ = this.dialogDom_.querySelector('#delete-button'); |
514 this.table_ = this.dialogDom_.querySelector('.detail-table'); | 465 this.table_ = this.dialogDom_.querySelector('.detail-table'); |
515 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid'); | 466 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid'); |
516 this.spinner_ = this.dialogDom_.querySelector('.spinner'); | 467 this.spinner_ = this.dialogDom_.querySelector('.spinner'); |
517 this.showSpinner_(false); | 468 this.showSpinner_(false); |
518 this.butter_ = this.dialogDom_.querySelector('.butter-bar'); | 469 this.butter_ = this.dialogDom_.querySelector('.butter-bar'); |
519 this.unmountedPanel_ = this.dialogDom_.querySelector('.unmounted-panel'); | |
520 | 470 |
521 cr.ui.decorate('#gdata-settings', cr.ui.MenuButton); | 471 cr.ui.decorate('#gdata-settings', cr.ui.MenuButton); |
522 cr.ui.Table.decorate(this.table_); | 472 cr.ui.Table.decorate(this.table_); |
523 cr.ui.Grid.decorate(this.grid_); | 473 cr.ui.Grid.decorate(this.grid_); |
524 | 474 |
525 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); | 475 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); |
526 // Disable the default browser context menu. | 476 // Disable the default browser context menu. |
527 this.document_.addEventListener('contextmenu', | 477 this.document_.addEventListener('contextmenu', |
528 function(e) { e.preventDefault() }); | 478 function(e) { e.preventDefault() }); |
529 | 479 |
(...skipping 29 matching lines...) Expand all Loading... | |
559 | 509 |
560 this.decorateSplitter( | 510 this.decorateSplitter( |
561 this.dialogDom_.querySelector('div.sidebar-splitter')); | 511 this.dialogDom_.querySelector('div.sidebar-splitter')); |
562 | 512 |
563 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); | 513 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); |
564 this.dialogDom_.querySelector('#detail-view').addEventListener( | 514 this.dialogDom_.querySelector('#detail-view').addEventListener( |
565 'click', this.onDetailViewButtonClick_.bind(this)); | 515 'click', this.onDetailViewButtonClick_.bind(this)); |
566 this.dialogDom_.querySelector('#thumbnail-view').addEventListener( | 516 this.dialogDom_.querySelector('#thumbnail-view').addEventListener( |
567 'click', this.onThumbnailViewButtonClick_.bind(this)); | 517 'click', this.onThumbnailViewButtonClick_.bind(this)); |
568 | 518 |
569 // When we show the page for the first time we want to avoid | |
570 // the GDrive settings button animation, so we set the attribute ASAP. | |
571 if (this.isStartingOnGData_()) | |
572 this.dialogContainer_.setAttribute('gdata', true); | |
573 | |
574 this.syncButton = this.dialogDom_.querySelector('#gdata-sync-settings'); | 519 this.syncButton = this.dialogDom_.querySelector('#gdata-sync-settings'); |
575 this.syncButton.addEventListener('click', this.onGDataPrefClick_.bind( | 520 this.syncButton.addEventListener('click', this.onGDataPrefClick_.bind( |
576 this, 'cellularDisabled', false /* not inverted */)); | 521 this, 'cellularDisabled', false /* not inverted */)); |
577 | 522 |
578 this.hostedButton = this.dialogDom_.querySelector('#gdata-hosted-settings'); | 523 this.hostedButton = this.dialogDom_.querySelector('#gdata-hosted-settings'); |
579 this.hostedButton.addEventListener('click', this.onGDataPrefClick_.bind( | 524 this.hostedButton.addEventListener('click', this.onGDataPrefClick_.bind( |
580 this, 'hostedFilesDisabled', true /* inverted */)); | 525 this, 'hostedFilesDisabled', true /* inverted */)); |
581 | 526 |
582 this.gdataPreferences_ = null; | 527 this.gdataPreferences_ = null; |
583 var queryGDataPreferences = function() { | 528 var queryGDataPreferences = function() { |
584 chrome.fileBrowserPrivate.getGDataPreferences( | 529 chrome.fileBrowserPrivate.getGDataPreferences( |
585 this.onGDataPreferencesChanged_.bind(this)); | 530 this.onGDataPreferencesChanged_.bind(this)); |
586 }.bind(this); | 531 }.bind(this); |
587 queryGDataPreferences(); | 532 queryGDataPreferences(); |
588 chrome.fileBrowserPrivate.onGDataPreferencesChanged. | 533 // TODO(serya): uncomment |
589 addListener(queryGDataPreferences); | 534 //chrome.fileBrowserPrivate.onGDataPreferencesChanged. |
535 // addListener(queryGDataPreferences); | |
590 | 536 |
591 cr.ui.ComboButton.decorate(this.taskItems_); | 537 cr.ui.ComboButton.decorate(this.taskItems_); |
592 this.taskItems_.addEventListener('select', | 538 this.taskItems_.addEventListener('select', |
593 this.onTaskItemClicked_.bind(this)); | 539 this.onTaskItemClicked_.bind(this)); |
594 | 540 |
595 this.dialogDom_.ownerDocument.defaultView.addEventListener( | 541 this.dialogDom_.ownerDocument.defaultView.addEventListener( |
596 'resize', this.onResize_.bind(this)); | 542 'resize', this.onResize_.bind(this)); |
597 | 543 |
598 if (str('ASH') == '1') | 544 if (str('ASH') == '1') |
599 this.dialogDom_.setAttribute('ash', 'true'); | 545 this.dialogDom_.setAttribute('ash', 'true'); |
(...skipping 19 matching lines...) Expand all Loading... | |
619 | 565 |
620 var sigleSelection = | 566 var sigleSelection = |
621 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || | 567 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || |
622 this.dialogType_ == FileManager.DialogType.SELECT_FOLDER || | 568 this.dialogType_ == FileManager.DialogType.SELECT_FOLDER || |
623 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE; | 569 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE; |
624 | 570 |
625 this.directoryModel_ = new DirectoryModel( | 571 this.directoryModel_ = new DirectoryModel( |
626 this.filesystem_.root, | 572 this.filesystem_.root, |
627 sigleSelection, | 573 sigleSelection, |
628 FileManager.isGDataEnabled(), | 574 FileManager.isGDataEnabled(), |
629 this.metadataCache_); | 575 this.metadataCache_, |
576 VolumeManager.getInstance()); | |
577 | |
578 this.fileWatcher_ = new FileWatcher(this.filesystem_.root, | |
579 this.directoryModel_, | |
580 VolumeManager.getInstance()); | |
581 this.fileWatcher_.start(); | |
630 | 582 |
631 if (FileManager.isGDataEnabled()) | 583 if (FileManager.isGDataEnabled()) |
632 this.initGDataWelcomeBanners_(); | 584 this.initGDataWelcomeBanners_(); |
633 | 585 |
634 var dataModel = this.directoryModel_.getFileList(); | 586 var dataModel = this.directoryModel_.getFileList(); |
635 var collator = this.collator_; | 587 var collator = this.collator_; |
636 // TODO(dgozman): refactor comparison functions together with | 588 // TODO(dgozman): refactor comparison functions together with |
637 // render/update/display. | 589 // render/update/display. |
638 dataModel.setCompareFunction('name', function(a, b) { | 590 dataModel.setCompareFunction('name', function(a, b) { |
639 return collator.compare(a.name, b.name); | 591 return collator.compare(a.name, b.name); |
(...skipping 17 matching lines...) Expand all Loading... | |
657 this.initGrid_(); | 609 this.initGrid_(); |
658 this.initRootsList_(); | 610 this.initRootsList_(); |
659 | 611 |
660 var listType = FileManager.ListType.DETAIL; | 612 var listType = FileManager.ListType.DETAIL; |
661 if (FileManager.DialogType.isModal(this.dialogType_)) | 613 if (FileManager.DialogType.isModal(this.dialogType_)) |
662 listType = window.localStorage['listType-' + this.dialogType_] || | 614 listType = window.localStorage['listType-' + this.dialogType_] || |
663 FileManager.ListType.DETAIL; | 615 FileManager.ListType.DETAIL; |
664 this.setListType(listType); | 616 this.setListType(listType); |
665 | 617 |
666 this.textSearchState_ = {text: '', date: new Date()}; | 618 this.textSearchState_ = {text: '', date: new Date()}; |
619 | |
620 this.volumeManager_.addEventListener('gdata-status-changed', | |
621 this.updateGDataStatus_.bind(this)); | |
667 }; | 622 }; |
668 | 623 |
669 FileManager.prototype.initRootsList_ = function() { | 624 FileManager.prototype.initRootsList_ = function() { |
670 this.rootsList_ = this.dialogDom_.querySelector('#roots-list'); | 625 this.rootsList_ = this.dialogDom_.querySelector('#roots-list'); |
671 cr.ui.List.decorate(this.rootsList_); | 626 cr.ui.List.decorate(this.rootsList_); |
672 this.rootsList_.startBatchUpdates(); | |
673 | 627 |
674 var self = this; | 628 var self = this; |
675 this.rootsList_.itemConstructor = function(entry) { | 629 this.rootsList_.itemConstructor = function(entry) { |
676 return self.renderRoot_(entry); | 630 return self.renderRoot_(entry); |
677 }; | 631 }; |
678 | 632 |
679 this.rootsList_.selectionModel = | 633 this.rootsList_.selectionModel = |
680 this.directoryModel_.getRootsListSelectionModel(); | 634 this.directoryModel_.getRootsListSelectionModel(); |
681 | 635 |
682 // TODO(dgozman): add "Add a drive" item. | 636 // TODO(dgozman): add "Add a drive" item. |
683 this.rootsList_.dataModel = this.directoryModel_.getRootsList(); | 637 this.rootsList_.dataModel = this.directoryModel_.getRootsList(); |
684 this.directoryModel_.updateRoots(function() { | |
685 self.rootsList_.endBatchUpdates(); | |
686 }, false); | |
687 }; | 638 }; |
688 | 639 |
689 /** | 640 FileManager.prototype.updateGDataStatus_ = function() { |
690 * @param {boolean} dirChanged True if we just changed to GData directory, | 641 var node = this.dialogContainer_; |
691 * False if "Retry" button clicked. | 642 if (this.isOnGData()) { |
692 */ | 643 var status = this.volumeManager_.getGDataStatus(); |
693 FileManager.prototype.initGData_ = function(dirChanged) { | 644 if (status == VolumeManager.GDataStatus.MOUNTING || |
694 this.initGDataUnmountedPanel_(); | 645 status == VolumeManager.GDataStatus.ERROR) { |
695 | 646 this.initGDataUnmountedPanel_(); |
696 this.unmountedPanel_.removeAttribute('error'); | |
697 if (dirChanged) { | |
698 // When changing to GData directory we want to see a clear panel. | |
699 this.unmountedPanel_.removeAttribute('retry'); | |
700 if (this.gdataLoadingTimer_) { // Show immediately if already loading. | |
701 this.unmountedPanel_.setAttribute('loading', true); | |
702 } else { | |
703 this.unmountedPanel_.removeAttribute('loading'); | |
704 setTimeout(function() { | |
705 if (this.gdataLoadingTimer_) { // Still loading. | |
706 this.unmountedPanel_.setAttribute('loading', true); | |
707 } | |
708 }.bind(this), 500); | |
709 } | 647 } |
648 node.setAttribute('gdata', status); | |
710 } else { | 649 } else { |
711 // When retrying we do not hide "Retry" and "Learn more". | 650 node.removeAttribute('gdata'); |
712 this.unmountedPanel_.setAttribute('loading', true); | |
713 } | 651 } |
714 | 652 console.log('gdata status: ', node.getAttribute('gdata')); |
715 // If the user changed to another directory and then back to GData we | |
716 // re-enter this method while the timer is still active. In this case | |
717 // we only update the UI but do not request the mount again. | |
718 if (this.gdataLoadingTimer_) | |
719 return; | |
720 | |
721 metrics.startInterval('Load.GData'); | |
722 chrome.fileBrowserPrivate.addMount('', 'gdata', {}, | |
723 function(sourcePath) {}); | |
724 | |
725 // This timer could fire before the mount succeeds. We will silently | |
726 // replace the error message with the correct directory contents. | |
727 this.gdataLoadingTimer_ = setTimeout(function() { | |
728 this.gdataLoadingTimer_ = null; | |
729 this.onGDataUnreachable_('GData load timeout'); | |
730 }.bind(this), | |
731 15 * 60 * 1000); | |
732 }; | |
733 | |
734 FileManager.prototype.clearGDataLoadingTimer_ = function(message) { | |
735 if (this.gdataLoadingTimer_) { | |
736 clearTimeout(this.gdataLoadingTimer_); | |
737 this.gdataLoadingTimer_ = null; | |
738 } | |
739 }; | |
740 | |
741 FileManager.prototype.onGDataUnreachable_ = function(message) { | |
742 console.warn(message); | |
743 if (this.isOnGData()) { | |
744 this.unmountedPanel_.removeAttribute('loading'); | |
745 this.unmountedPanel_.setAttribute('error', true); | |
746 this.unmountedPanel_.setAttribute('retry', true); | |
747 } | |
748 }; | 653 }; |
749 | 654 |
750 FileManager.prototype.initGDataUnmountedPanel_ = function() { | 655 FileManager.prototype.initGDataUnmountedPanel_ = function() { |
751 if (this.unmountedPanel_.firstElementChild) | 656 var panel = this.document_.querySelector('#unmounted-panel'); |
657 if (panel.firstElementChild) | |
752 return; | 658 return; |
753 | 659 |
754 var loading = this.document_.createElement('div'); | 660 function create(tag, className) { |
755 loading.className = 'gdata loading'; | 661 var div = panel.ownerDocument.createElement(tag); |
756 loading.textContent = str('GDATA_LOADING'); | 662 div.className = className; |
757 this.unmountedPanel_.appendChild(loading); | 663 return div; |
664 } | |
758 | 665 |
759 var spinnerBox = this.document_.createElement('div'); | 666 function append(tag, className, opt_textContent) { |
760 spinnerBox.className = 'spinner-box'; | 667 var div = create(tag, className); |
761 loading.appendChild(spinnerBox); | 668 div.textContent = opt_textContent | ''; |
669 panel.appendChild(div); | |
670 return div; | |
671 } | |
762 | 672 |
763 var spinner = this.document_.createElement('div'); | 673 append('div', 'gdata loading', str('GDATA_LOADING')); |
764 spinner.className = 'spinner'; | 674 append('div', 'spinner-box').appendChild(create('div', 'spinner')); |
765 spinnerBox.appendChild(spinner); | 675 var progress = append('div', 'gdata progress'); |
766 | |
767 var progress = this.document_.createElement('div'); | |
768 progress.className = 'gdata progress'; | |
769 this.unmountedPanel_.appendChild(progress); | |
770 | |
771 chrome.fileBrowserPrivate.onDocumentFeedFetched.addListener( | 676 chrome.fileBrowserPrivate.onDocumentFeedFetched.addListener( |
772 function(fileCount) { | 677 function(fileCount) { |
773 progress.textContent = strf('GDATA_LOADING_PROGRESS', fileCount); | 678 progress.textContent = strf('GDATA_LOADING_PROGRESS', fileCount); |
774 }); | 679 }); |
775 | 680 |
776 var error = this.document_.createElement('div'); | 681 append('div', 'gdata error', strf('GDATA_CANNOT_REACH', |
777 error.className = 'gdata error'; | 682 str('GDATA_PRODUCT_NAME'))); |
778 error.textContent = strf('GDATA_CANNOT_REACH', str('GDATA_PRODUCT_NAME')); | |
779 this.unmountedPanel_.appendChild(error); | |
780 | 683 |
781 var retry = this.document_.createElement('button'); | 684 append('button', 'gdata retry', str('GDATA_RETRY')); |
782 retry.className = 'gdata retry'; | 685 // onclick = this.initGData_.bind(this, false); |
783 retry.textContent = str('GDATA_RETRY'); | |
784 retry.onclick = this.initGData_.bind(this, false /* retry */); | |
785 this.unmountedPanel_.appendChild(retry); | |
786 | 686 |
787 var learnMore = this.document_.createElement('div'); | 687 append('div', 'gdata learn-more plain-link', str('GDATA_LEARN_MORE')). |
788 learnMore.className = 'gdata learn-more plain-link'; | 688 onclick = this.onExternalLinkClick_.bind(this, |
789 learnMore.textContent = str('GDATA_LEARN_MORE'); | 689 GOOGLE_DRIVE_ERROR_HELP_URL); |
790 learnMore.addEventListener('click', | |
791 this.onExternalLinkClick_.bind(this, GOOGLE_DRIVE_ERROR_HELP_URL)); | |
792 this.unmountedPanel_.appendChild(learnMore); | |
793 }; | 690 }; |
794 | 691 |
795 FileManager.prototype.onDataModelSplice_ = function(event) { | 692 FileManager.prototype.onDataModelSplice_ = function(event) { |
796 var checkbox = this.document_.querySelector('#select-all-checkbox'); | 693 var checkbox = this.document_.querySelector('#select-all-checkbox'); |
797 if (checkbox) | 694 if (checkbox) |
798 this.updateSelectAllCheckboxState_(checkbox); | 695 this.updateSelectAllCheckboxState_(checkbox); |
799 }; | 696 }; |
800 | 697 |
801 FileManager.prototype.onDataModelPermuted_ = function(event) { | 698 FileManager.prototype.onDataModelPermuted_ = function(event) { |
802 var sortStatus = this.directoryModel_.getFileList().sortStatus; | 699 var sortStatus = this.directoryModel_.getFileList().sortStatus; |
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1333 | 1230 |
1334 case 'delete': | 1231 case 'delete': |
1335 this.deleteEntries(this.selection.entries); | 1232 this.deleteEntries(this.selection.entries); |
1336 return; | 1233 return; |
1337 | 1234 |
1338 case 'newfolder': | 1235 case 'newfolder': |
1339 this.onNewFolderCommand_(event); | 1236 this.onNewFolderCommand_(event); |
1340 return; | 1237 return; |
1341 | 1238 |
1342 case 'unmount': | 1239 case 'unmount': |
1343 this.unmountVolume_(this.directoryModel_.getCurrentRootDirEntry()); | 1240 this.unmountVolume_( |
1241 this.directoryModel_.getCurrentRootDirEntry()); | |
1344 return; | 1242 return; |
1345 | 1243 |
1346 case 'format': | 1244 case 'format': |
1347 var entry = this.directoryModel_.getCurrentRootDirEntry(); | 1245 var entry = this.directoryModel_.getCurrentRootDirEntry(); |
1348 this.confirm.show(str('FORMATTING_WARNING'), function() { | 1246 this.confirm.show(str('FORMATTING_WARNING'), function() { |
1349 chrome.fileBrowserPrivate.formatDevice(entry.toURL()); | 1247 chrome.fileBrowserPrivate.formatDevice(entry.toURL()); |
1350 }); | 1248 }); |
1351 | 1249 |
1352 return; | 1250 return; |
1353 } | 1251 } |
1354 }; | 1252 }; |
1355 | 1253 |
1356 /** | 1254 /** |
1357 * Respond to the back and forward buttons. | 1255 * Respond to the back and forward buttons. |
1358 */ | 1256 */ |
1359 FileManager.prototype.onPopState_ = function(event) { | 1257 FileManager.prototype.onPopState_ = function(event) { |
1360 this.closeFilePopup_(); | 1258 this.closeFilePopup_(); |
1361 // Nothing left to do if the current directory is not changing. This happens | 1259 // Nothing left to do if the current directory is not changing. This happens |
1362 // if we are exiting the Gallery. | 1260 // if we are exiting the Gallery. |
1363 if (this.getPathFromUrlOrParams_() == | 1261 if (this.getPathFromUrlOrParams_() == |
1364 this.directoryModel_.getCurrentDirEntry().fullPath) | 1262 this.directoryModel_.getCurrentDirEntry().fullPath) |
1365 return; | 1263 return; |
1366 this.setupCurrentDirectory_(true /* invokeHandler */); | 1264 this.setupCurrentDirectory_(false /* page loading */); |
1367 }; | 1265 }; |
1368 | 1266 |
1369 FileManager.prototype.requestResize_ = function(timeout) { | 1267 FileManager.prototype.requestResize_ = function(timeout) { |
1370 setTimeout(this.onResize_.bind(this), timeout || 0); | 1268 setTimeout(this.onResize_.bind(this), timeout || 0); |
1371 }; | 1269 }; |
1372 | 1270 |
1373 /** | 1271 /** |
1374 * Resize details and thumb views to fit the new window size. | 1272 * Resize details and thumb views to fit the new window size. |
1375 */ | 1273 */ |
1376 FileManager.prototype.onResize_ = function() { | 1274 FileManager.prototype.onResize_ = function() { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1410 }; | 1308 }; |
1411 | 1309 |
1412 /** | 1310 /** |
1413 * Restores current directory and may be a selected item after page load (or | 1311 * Restores current directory and may be a selected item after page load (or |
1414 * reload) or popping a state (after click on back/forward). If location.hash | 1312 * reload) or popping a state (after click on back/forward). If location.hash |
1415 * is present it means that the user has navigated somewhere and that place | 1313 * is present it means that the user has navigated somewhere and that place |
1416 * will be restored. defaultPath primarily is used with save/open dialogs. | 1314 * will be restored. defaultPath primarily is used with save/open dialogs. |
1417 * Default path may also contain a file name. Freshly opened file manager | 1315 * Default path may also contain a file name. Freshly opened file manager |
1418 * window has neither. | 1316 * window has neither. |
1419 * | 1317 * |
1420 * @param {boolean} invokeHandler Whether to invoke the default handler on | 1318 * @param {boolean} invokeHandler Whether to invoke the default handler on |
Vladislav Kaznacheev
2012/05/15 11:11:54
We do need the |invokeHandler| parameter. I cannot
SeRya
2012/05/15 18:16:20
|invokeHandler| was inlined in place. I added invo
| |
1421 * the selected file. | 1319 * the selected file. |
1422 * @param {boolean} opt_blankWhileOpeningAFile Whether to show fade over | 1320 * @param {boolean} opt_blankWhileOpeningAFile Whether to show fade over |
1423 * the file manager. | 1321 * the file manager. |
1424 */ | 1322 */ |
1425 FileManager.prototype.setupCurrentDirectory_ = | 1323 FileManager.prototype.setupCurrentDirectory_ = function(pageLoading) { |
1426 function(invokeHandler, opt_blankWhileOpeningAFile) { | |
1427 var path = this.getPathFromUrlOrParams_(); | 1324 var path = this.getPathFromUrlOrParams_(); |
1428 | 1325 |
1429 if (!path) { | 1326 if (!path) { |
1430 this.directoryModel_.setupDefaultPath(); | 1327 this.directoryModel_.setupDefaultPath(); |
1431 return; | 1328 return; |
1432 } | 1329 } |
1433 | 1330 |
1331 if (DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA) { | |
1332 if (!FileManager.isGDataEnabled()) { | |
1333 this.directoryModel_.setupDefaultPath(); | |
1334 return; | |
1335 } | |
1336 | |
1337 // Reflect immediatelly in the UI we are on GData and display | |
1338 // mounting UI. | |
1339 this.directoryModel_.setupPath('/' + DirectoryModel.GDATA_DIRECTORY); | |
1340 | |
1341 var tracker = this.directoryModel_.createDirectoryChangeTracker(); | |
1342 // Expected finish of setupPath to GData. | |
1343 tracker.exceptInitialChange = true; | |
1344 tracker.start(); | |
1345 this.volumeManager_.mountGData(function() { | |
1346 tracker.stop(); | |
1347 if (!tracker.hasChanged) { | |
1348 this.finishSetupCurrentDirectory_(path, pageLoading); | |
1349 } | |
1350 }.bind(this), function(error) { | |
1351 tracker.stop(); | |
1352 }); | |
1353 } else { | |
1354 this.finishSetupCurrentDirectory_(path, pageLoading); | |
1355 } | |
1356 }; | |
1357 | |
1358 FileManager.prototype.finishSetupCurrentDirectory_ = function( | |
1359 path, pageLoading) { | |
1434 // In the FULL_PAGE mode if the hash path points to a file we might have | 1360 // In the FULL_PAGE mode if the hash path points to a file we might have |
1435 // to invoke a task after selecting it. | 1361 // to invoke a task after selecting it. |
1436 // If the file path is in params_ we only want to select the file. | 1362 // If the file path is in params_ we only want to select the file. |
1437 if (invokeHandler && location.hash && | 1363 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE && |
1438 this.dialogType_ == FileManager.DialogType.FULL_PAGE) { | 1364 location.hash && (!pageLoading || !this.params_.selectOnly)) { |
1439 // To prevent the file list flickering for a moment before the action | 1365 // To prevent the file list flickering for a moment before the action |
1440 // is executed we hide it under a white div. | 1366 // is executed we hide it under a white div. |
1441 var shade; | 1367 var shade; |
1442 if (opt_blankWhileOpeningAFile) { | 1368 if (pageLoading) { |
1443 shade = this.document_.createElement('div'); | 1369 shade = this.document_.createElement('div'); |
1444 shade.className = 'overlay-pane'; | 1370 shade.className = 'overlay-pane'; |
1445 shade.style.backgroundColor = 'white'; | 1371 shade.style.backgroundColor = 'white'; |
1446 this.document_.body.appendChild(shade); | 1372 this.document_.body.appendChild(shade); |
1447 } | 1373 } |
1448 function removeShade() { | 1374 function removeShade() { |
1449 if (shade) | 1375 if (shade) |
1450 shade.parentNode.removeChild(shade); | 1376 shade.parentNode.removeChild(shade); |
1451 } | 1377 } |
1452 | 1378 |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1768 } | 1694 } |
1769 }; | 1695 }; |
1770 li.addEventListener('mousedown', handleClick); | 1696 li.addEventListener('mousedown', handleClick); |
1771 li.addEventListener(cr.ui.TouchHandler.EventType.TOUCH_START, handleClick); | 1697 li.addEventListener(cr.ui.TouchHandler.EventType.TOUCH_START, handleClick); |
1772 | 1698 |
1773 var rootType = DirectoryModel.getRootType(entry.fullPath); | 1699 var rootType = DirectoryModel.getRootType(entry.fullPath); |
1774 | 1700 |
1775 var div = this.document_.createElement('div'); | 1701 var div = this.document_.createElement('div'); |
1776 div.className = 'root-label'; | 1702 div.className = 'root-label'; |
1777 | 1703 |
1778 var icon = rootType; | |
1779 var deviceNumber = this.getDeviceNumber(entry); | |
1780 | |
1781 if (deviceNumber != undefined) { | |
1782 var mountCondition = this.mountPoints_[deviceNumber].mountCondition; | |
1783 if (mountCondition == 'unknown_filesystem' || | |
1784 mountCondition == 'unsupported_filesystem') | |
1785 icon = 'unreadable'; | |
1786 } | |
1787 | |
1788 div.setAttribute('icon', icon); | |
1789 | |
1790 div.textContent = this.getRootLabel_(entry.fullPath); | 1704 div.textContent = this.getRootLabel_(entry.fullPath); |
1791 li.appendChild(div); | 1705 li.appendChild(div); |
1792 | 1706 |
1793 if (rootType == DirectoryModel.RootType.ARCHIVE || | 1707 if (rootType == DirectoryModel.RootType.ARCHIVE || |
1794 rootType == DirectoryModel.RootType.REMOVABLE) { | 1708 rootType == DirectoryModel.RootType.REMOVABLE) { |
1795 if (entry.unmounting) { | 1709 var eject = this.document_.createElement('div'); |
1796 li.setAttribute('disabled', 'disabled'); | 1710 eject.className = 'root-eject'; |
1797 } else { | 1711 eject.addEventListener('click', function(event) { |
1798 var eject = this.document_.createElement('div'); | 1712 event.stopPropagation(); |
1799 eject.className = 'root-eject'; | 1713 this.unmountVolume_(entry); |
1800 eject.addEventListener('click', function(event) { | 1714 }.bind(this)); |
1801 event.stopPropagation(); | 1715 // Block other mouse handlers. |
1802 this.unmountVolume_(entry); | 1716 eject.addEventListener('mouseup', function(e) { e.stopPropagation() }); |
1803 }.bind(this)); | 1717 eject.addEventListener('mousedown', function(e) { e.stopPropagation() }); |
1804 // Block other mouse handlers. | 1718 li.appendChild(eject); |
1805 eject.addEventListener('mouseup', function(e) { e.stopPropagation() }); | |
1806 eject.addEventListener('mousedown', function(e) { e.stopPropagation() }) ; | |
1807 li.appendChild(eject); | |
1808 | 1719 |
1809 cr.ui.contextMenuHandler.setContextMenu(li, this.rootsContextMenu_); | 1720 cr.ui.contextMenuHandler.setContextMenu(li, this.rootsContextMenu_); |
1810 } | |
1811 } | 1721 } |
1812 | 1722 |
1813 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); | 1723 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); |
1814 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); | 1724 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); |
1725 | |
1726 var icon = rootType; | |
1727 var mountCondition = this.volumeManager_.getMountCondition(entry.fullPath); | |
1728 | |
1729 if (mountCondition == 'unknown_filesystem' || | |
1730 mountCondition == 'unsupported_filesystem') { | |
1731 icon = 'unreadable'; | |
1732 } | |
1733 div.setAttribute('icon', icon); | |
1734 | |
1815 return li; | 1735 return li; |
1816 }; | 1736 }; |
1817 | 1737 |
1818 /** | 1738 /** |
1819 * Unmounts device. | 1739 * Unmounts device. |
1820 * @param {Entry} entry The entry to unmount. | 1740 * @param {Entry} entry The entry to unmount. |
1821 */ | 1741 */ |
1822 FileManager.prototype.unmountVolume_ = function(entry) { | 1742 FileManager.prototype.unmountVolume_ = function(entry) { |
1823 this.directoryModel_.prepareUnmount(entry.fullPath); | 1743 listItem = this.rootsList_.fileListItem(entry); |
1824 this.unmountRequests_.push(entry.fullPath); | 1744 listItem && listItem.setAttribute('disabled'); |
1825 chrome.fileBrowserPrivate.removeMount(entry.toURL()); | 1745 var self = this; |
1746 this.volumeManager_.unmount(entry.fullPath, function() {}, | |
1747 function(error) { | |
1748 listItem && listItem.removeAttribute('disabled'); | |
1749 self.alert.show(strf('UNMOUNT_FAILED', error.message)); | |
1750 }); | |
1826 }; | 1751 }; |
1827 | 1752 |
1828 FileManager.prototype.updateGDataStyle_ = function( | 1753 FileManager.prototype.updateGDataStyle_ = function( |
1829 listItem, entry, gdata) { | 1754 listItem, entry, gdata) { |
1830 if (!this.isOnGData() || !gdata) | 1755 if (!this.isOnGData() || !gdata) |
1831 return; | 1756 return; |
1832 | 1757 |
1833 if (!entry.isDirectory) { | 1758 if (!entry.isDirectory) { |
1834 if (!gdata.availableOffline) | 1759 if (!gdata.availableOffline) |
1835 listItem.classList.add('dim-offline'); | 1760 listItem.classList.add('dim-offline'); |
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2193 selection.bytes += filesystem.size; | 2118 selection.bytes += filesystem.size; |
2194 } | 2119 } |
2195 } | 2120 } |
2196 | 2121 |
2197 this.dispatchEvent(new cr.Event('selection-summarized')); | 2122 this.dispatchEvent(new cr.Event('selection-summarized')); |
2198 }.bind(this)); | 2123 }.bind(this)); |
2199 | 2124 |
2200 if (this.isOnGData()) { | 2125 if (this.isOnGData()) { |
2201 this.metadataCache_.get(selection.urls, 'gdata', function(props) { | 2126 this.metadataCache_.get(selection.urls, 'gdata', function(props) { |
2202 selection.allGDataFilesPresent = | 2127 selection.allGDataFilesPresent = |
2203 props.filter(function(p) {return !p.availableOffline}).length == 0; | 2128 props.filter(function(p) {return p && !p.availableOffline}).length = = 0; |
2204 this.updateOkButton_(); | 2129 this.updateOkButton_(); |
2205 }.bind(this)); | 2130 }.bind(this)); |
2206 } | 2131 } |
2207 }; | 2132 }; |
2208 | 2133 |
2209 /** | 2134 /** |
2210 * Check if all the files in the current selection are available. The only | 2135 * Check if all the files in the current selection are available. The only |
2211 * case when files might be not available is when the selection contains | 2136 * case when files might be not available is when the selection contains |
2212 * uncached GData files and the browser is offline. | 2137 * uncached GData files and the browser is offline. |
2213 * @return {boolean} True if all files in the current selection are | 2138 * @return {boolean} True if all files in the current selection are |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2625 }; | 2550 }; |
2626 | 2551 |
2627 FileManager.prototype.isOffline = function() { | 2552 FileManager.prototype.isOffline = function() { |
2628 return this.networkConnectionState_ && !this.networkConnectionState_.online; | 2553 return this.networkConnectionState_ && !this.networkConnectionState_.online; |
2629 }; | 2554 }; |
2630 | 2555 |
2631 FileManager.prototype.isOnReadonlyDirectory = function() { | 2556 FileManager.prototype.isOnReadonlyDirectory = function() { |
2632 return this.directoryModel_.isReadOnly(); | 2557 return this.directoryModel_.isReadOnly(); |
2633 }; | 2558 }; |
2634 | 2559 |
2635 /** | 2560 // TODO(serya): close tab on unmount. |
2636 * Event handler called when some volume was mounted or unmouted. | 2561 FileManager.prototype.onVolumeUnmounted_ = function(event) { |
2637 */ | 2562 if (event.mountPath == dm.getCurrentRootPath()) { |
2638 FileManager.prototype.onMountCompleted_ = function(event) { | 2563 if (this.params_.mountTriggered && !event.requested) { |
2639 var changeDirectoryTo = null; | 2564 // TODO(serya): What if 2 USB sticks plugged? |
2640 | 2565 chrome.tabs.getCurrent(function(tab) { |
2641 if (event && event.mountType == 'gdata') { | 2566 chrome.tabs.remove(tab.id); |
2642 var mounted = (event.eventType == 'mount'); | 2567 }); |
2643 metrics.recordInterval('Load.GData'); | |
2644 console.log('GData ' + (mounted ? 'mounted' : 'unmounted')); | |
2645 if (mounted && event.status == 'success') { | |
2646 this.gdataMounted_ = true; | |
2647 this.gdataMountInfo_ = { | |
2648 'mountPath': event.mountPath, | |
2649 'sourcePath': event.sourcePath, | |
2650 'mountType': event.mountType, | |
2651 'mountCondition': event.status | |
2652 }; | |
2653 // Not calling clearGDataLoadingTimer_ here because we want to keep | |
2654 // "Loading Google Docs" message until the directory loads. It is OK if | |
2655 // the timer fires after the mount because onDirectoryChanged_ will hide | |
2656 // the unmounted panel. | |
2657 if (this.setupCurrentDirectoryPostponed_) { | |
2658 this.setupCurrentDirectoryPostponed_(false /* execute */); | |
2659 } else if (this.isOnGData() && | |
2660 this.directoryModel_.getCurrentDirEntry().unmounted) { | |
2661 // We are currently on an unmounted GData directory, force a rescan. | |
2662 changeDirectoryTo = this.directoryModel_.getCurrentRootPath(); | |
2663 } | |
2664 } else { | |
2665 this.gdataMounted_ = false; | |
2666 this.gdataMountInfo_ = null; | |
2667 this.clearGDataLoadingTimer_(); | |
2668 this.onGDataUnreachable_('GData ' + | |
2669 (mounted ? ('mount failed: ' + event.status) : 'unmounted')); | |
2670 if (this.setupCurrentDirectoryPostponed_) { | |
2671 this.setupCurrentDirectoryPostponed_(true /* cancel */); | |
2672 // Change to unmounted GData root. | |
2673 changeDirectoryTo = '/' + DirectoryModel.GDATA_DIRECTORY; | |
2674 } | |
2675 } | 2568 } |
2676 } | 2569 } |
2677 | |
2678 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { | |
2679 this.setMountPoints_(mountPoints); | |
2680 | |
2681 if (event.eventType == 'mount') { | |
2682 // Mount request finished - remove it. | |
2683 // Currently we only request mounts for archive files. | |
2684 var index = this.mountRequests_.indexOf(event.sourcePath); | |
2685 if (index != -1) { | |
2686 this.mountRequests_.splice(index, 1); | |
2687 if (event.status == 'success') { | |
2688 // Successful mount requested from this tab, go to the drive root. | |
2689 changeDirectoryTo = event.mountPath; | |
2690 } else { | |
2691 // Request initiated from this tab failed, report the error. | |
2692 var fileName = event.sourcePath.split('/').pop(); | |
2693 this.alert.show( | |
2694 strf('ARCHIVE_MOUNT_FAILED', fileName, event.status)); | |
2695 } | |
2696 } | |
2697 } | |
2698 | |
2699 if (event.eventType == 'unmount') { | |
2700 // Unmount request finished - remove it. | |
2701 var index = this.unmountRequests_.indexOf(event.mountPath); | |
2702 if (index != -1) { | |
2703 this.unmountRequests_.splice(index, 1); | |
2704 if (event.status != 'success') | |
2705 this.alert.show(strf('UNMOUNT_FAILED', event.status)); | |
2706 } | |
2707 | |
2708 if (event.status == 'success' && | |
2709 event.mountPath == this.directoryModel_.getCurrentRootPath()) { | |
2710 if (this.params_.mountTriggered && index == -1) { | |
2711 // This device mount was the reason this File Manager instance was | |
2712 // created. Now the device is unmounted from another instance | |
2713 // or the user removed the device manually. Close this instance. | |
2714 // window.close() sometimes doesn't work. | |
2715 chrome.tabs.getCurrent(function(tab) { | |
2716 chrome.tabs.remove(tab.id); | |
2717 }); | |
2718 return; | |
2719 } | |
2720 // Current directory just unmounted. Move to the 'Downloads'. | |
2721 changeDirectoryTo = this.directoryModel_.getDefaultDirectory(); | |
2722 } | |
2723 } | |
2724 | |
2725 // Even if something failed root list should be rescanned. | |
2726 // Failed mounts can "give" us new devices which might be formatted, | |
2727 // so we have to refresh root list then. | |
2728 this.directoryModel_.updateRoots(function() { | |
2729 if (changeDirectoryTo) { | |
2730 this.directoryModel_.changeDirectory(changeDirectoryTo); | |
2731 } | |
2732 }.bind(this), this.gdataMounted_); | |
2733 }.bind(this)); | |
2734 }; | 2570 }; |
2735 | 2571 |
2736 /** | 2572 /** |
2737 * Event handler called when some internal task should be executed. | 2573 * Event handler called when some internal task should be executed. |
2738 */ | 2574 */ |
2739 FileManager.prototype.onFileTaskExecute_ = function(id, urls) { | 2575 FileManager.prototype.onFileTaskExecute_ = function(id, urls) { |
2740 if (id == 'play') { | 2576 if (id == 'play') { |
2741 var position = 0; | 2577 var position = 0; |
2742 if (urls.length == 1) { | 2578 if (urls.length == 1) { |
2743 // If just a single audio file is selected pass along every audio file | 2579 // If just a single audio file is selected pass along every audio file |
2744 // in the directory. | 2580 // in the directory. |
2745 var selectedUrl = urls[0]; | 2581 var selectedUrl = urls[0]; |
2746 urls = this.getAllUrlsInCurrentDirectory_().filter(FileType.isAudio); | 2582 urls = this.getAllUrlsInCurrentDirectory_().filter(FileType.isAudio); |
2747 position = urls.indexOf(selectedUrl); | 2583 position = urls.indexOf(selectedUrl); |
2748 } | 2584 } |
2749 chrome.mediaPlayerPrivate.play(urls, position); | 2585 chrome.mediaPlayerPrivate.play(urls, position); |
2750 } else if (id == 'mount-archive') { | 2586 } else if (id == 'mount-archive') { |
2751 var self = this; | 2587 var self = this; |
2588 var tracker = this.directoryModel_.createDirectoryChangeTracker(); | |
2589 tracker.start(); | |
2752 this.resolveSelectResults_(urls, function(urls) { | 2590 this.resolveSelectResults_(urls, function(urls) { |
2753 for (var index = 0; index < urls.length; ++index) { | 2591 for (var index = 0; index < urls.length; ++index) { |
2754 // Url in MountCompleted event won't be escaped, so let's make sure | 2592 var path = /^filesystem:[\w-]*:\/\/[\w]*\/external(\/.*)$/. |
2755 // we don't use escaped one in mountRequests_. | 2593 exec(urls[index])[1]; |
2756 var unescapedUrl = unescape(urls[index]); | 2594 if (!path) |
2757 chrome.fileBrowserPrivate.addMount(unescapedUrl, 'file', {}, | 2595 continue; |
2758 function(sourcePath) { | 2596 path = path.decodeURLComponent(path); |
2759 self.mountRequests_.push(sourcePath); | 2597 this.volumeManager_.mountArchive(path, function(mountPath) { |
2598 tracker.stop(); | |
2599 if (!tracker.hasChanged) | |
2600 self.directoryModel_.changeDirectory(mountPath); | |
2601 }, function(error) { | |
2602 tracker.stop(); | |
2603 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', | |
2604 error.fileName, error.message)); | |
2760 }); | 2605 }); |
2761 } | 2606 } |
2762 }); | 2607 }); |
2763 } else if (id == 'format-device') { | 2608 } else if (id == 'format-device') { |
2764 this.confirm.show(str('FORMATTING_WARNING'), function() { | 2609 this.confirm.show(str('FORMATTING_WARNING'), function() { |
2765 chrome.fileBrowserPrivate.formatDevice(urls[0]); | 2610 chrome.fileBrowserPrivate.formatDevice(urls[0]); |
2766 }); | 2611 }); |
2767 } else if (id == 'gallery') { | 2612 } else if (id == 'gallery') { |
2768 this.openGallery_(urls); | 2613 this.openGallery_(urls); |
2769 } else if (id == 'view-pdf' || id == 'view-in-browser' || | 2614 } else if (id == 'view-pdf' || id == 'view-in-browser' || |
2770 id == 'install-crx' || id == 'open-hosted') { | 2615 id == 'install-crx' || id == 'open-hosted') { |
2771 chrome.fileBrowserPrivate.viewFiles(urls, 'default', function(success) { | 2616 chrome.fileBrowserPrivate.viewFiles(urls, 'default', function(success) { |
2772 if (!success) | 2617 if (!success) |
2773 console.error('chrome.fileBrowserPrivate.viewFiles failed', urls); | 2618 console.error('chrome.fileBrowserPrivate.viewFiles failed', urls); |
2774 }); | 2619 }); |
2775 } | 2620 } |
2776 }; | 2621 }; |
2777 | 2622 |
2778 FileManager.prototype.getDeviceNumber = function(entry) { | |
2779 if (!entry.isDirectory) return undefined; | |
2780 for (var i = 0; i < this.mountPoints_.length; i++) { | |
2781 if (normalizeAbsolutePath(entry.fullPath) == | |
2782 normalizeAbsolutePath(this.mountPoints_[i].mountPath)) { | |
2783 return i; | |
2784 } | |
2785 } | |
2786 return undefined; | |
2787 }; | |
2788 | |
2789 /** | 2623 /** |
2790 * Show a modal-like file viewer/editor on top of the File Manager UI. | 2624 * Show a modal-like file viewer/editor on top of the File Manager UI. |
2791 * | 2625 * |
2792 * @param {HTMLElement} popup Popup element. | 2626 * @param {HTMLElement} popup Popup element. |
2793 * @param {function} closeCallback Function to call after the popup is closed. | 2627 * @param {function} closeCallback Function to call after the popup is closed. |
2794 */ | 2628 */ |
2795 FileManager.prototype.openFilePopup_ = function(popup, closeCallback) { | 2629 FileManager.prototype.openFilePopup_ = function(popup, closeCallback) { |
2796 this.closeFilePopup_(); | 2630 this.closeFilePopup_(); |
2797 this.filePopup_ = popup; | 2631 this.filePopup_ = popup; |
2798 this.filePopupCloseCallback_ = closeCallback; | 2632 this.filePopupCloseCallback_ = closeCallback; |
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3376 return true; | 3210 return true; |
3377 } | 3211 } |
3378 if (!this.okButton_.disabled) { | 3212 if (!this.okButton_.disabled) { |
3379 this.onOk_(); | 3213 this.onOk_(); |
3380 return true; | 3214 return true; |
3381 } | 3215 } |
3382 return false; | 3216 return false; |
3383 }; | 3217 }; |
3384 | 3218 |
3385 FileManager.prototype.onDirectoryAction = function(entry) { | 3219 FileManager.prototype.onDirectoryAction = function(entry) { |
3386 var deviceNumber = this.getDeviceNumber(entry); | 3220 var mountCondition = this.volumeManager_.getMountCondition(entry.fullPath); |
3387 if (deviceNumber != undefined && | 3221 if (mountCondition == 'unknown_filesystem') { |
3388 this.mountPoints_[deviceNumber].mountCondition == | |
3389 'unknown_filesystem') { | |
3390 return this.showButter(str('UNKNOWN_FILESYSTEM_WARNING')); | 3222 return this.showButter(str('UNKNOWN_FILESYSTEM_WARNING')); |
3391 } else if (deviceNumber != undefined && | 3223 } else if (mountCondition == 'unsupported_filesystem') { |
3392 this.mountPoints_[deviceNumber].mountCondition == | |
3393 'unsupported_filesystem') { | |
3394 return this.showButter(str('UNSUPPORTED_FILESYSTEM_WARNING')); | 3224 return this.showButter(str('UNSUPPORTED_FILESYSTEM_WARNING')); |
3395 } else { | 3225 } else { |
3396 return this.directoryModel_.changeDirectory(entry.fullPath); | 3226 return this.directoryModel_.changeDirectory(entry.fullPath); |
3397 } | 3227 } |
3398 }; | 3228 }; |
3399 | 3229 |
3400 /** | 3230 /** |
3401 * Show or hide the "Low disk space" warning. | 3231 * Show or hide the "Low disk space" warning. |
3402 * @param {boolean} show True if the box need to be shown. | 3232 * @param {boolean} show True if the box need to be shown. |
3403 */ | 3233 */ |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3457 | 3287 |
3458 // Sometimes we rescan the same directory (when mounting GData lazily first, | 3288 // Sometimes we rescan the same directory (when mounting GData lazily first, |
3459 // then for real). Do not update the location then. | 3289 // then for real). Do not update the location then. |
3460 if (event.newDirEntry.fullPath != event.previousDirEntry.fullPath) { | 3290 if (event.newDirEntry.fullPath != event.previousDirEntry.fullPath) { |
3461 this.updateLocation_(event.initial, event.newDirEntry.fullPath); | 3291 this.updateLocation_(event.initial, event.newDirEntry.fullPath); |
3462 } | 3292 } |
3463 | 3293 |
3464 this.checkFreeSpace_(this.getCurrentDirectory()); | 3294 this.checkFreeSpace_(this.getCurrentDirectory()); |
3465 | 3295 |
3466 this.updateTitle_(); | 3296 this.updateTitle_(); |
3297 this.updateGDataStatus_(); | |
3467 | 3298 |
3468 if (this.filesystemObserverId_) | 3299 if (this.filesystemObserverId_) |
3469 this.metadataCache_.removeObserver(this.filesystemObserverId_); | 3300 this.metadataCache_.removeObserver(this.filesystemObserverId_); |
3470 if (this.gdataObserverId_) | 3301 if (this.gdataObserverId_) |
3471 this.metadataCache_.removeObserver(this.gdataObserverId_); | 3302 this.metadataCache_.removeObserver(this.gdataObserverId_); |
3472 | 3303 |
3473 this.filesystemObserverId_ = this.metadataCache_.addObserver( | 3304 this.filesystemObserverId_ = this.metadataCache_.addObserver( |
3474 this.directoryModel_.getCurrentDirEntry(), | 3305 this.directoryModel_.getCurrentDirEntry(), |
3475 MetadataCache.CHILDREN, | 3306 MetadataCache.CHILDREN, |
3476 'filesystem', | 3307 'filesystem', |
3477 this.updateMetadataInUI_.bind(this, 'filesystem')); | 3308 this.updateMetadataInUI_.bind(this, 'filesystem')); |
3478 | 3309 |
3479 if (this.isOnGData()) { | 3310 if (this.isOnGData()) { |
3480 this.gdataObserverId_ = this.metadataCache_.addObserver( | 3311 this.gdataObserverId_ = this.metadataCache_.addObserver( |
3481 this.directoryModel_.getCurrentDirEntry(), | 3312 this.directoryModel_.getCurrentDirEntry(), |
3482 MetadataCache.CHILDREN, | 3313 MetadataCache.CHILDREN, |
3483 'gdata', | 3314 'gdata', |
3484 this.updateMetadataInUI_.bind(this, 'gdata')); | 3315 this.updateMetadataInUI_.bind(this, 'gdata')); |
3485 } | 3316 } |
3486 | |
3487 var self = this; | |
3488 | |
3489 if (this.watchedDirectoryUrl_) { | |
3490 if (this.watchedDirectoryUrl_ != event.previousDirEntry.toURL()) { | |
3491 console.warn('event.previousDirEntry does not match File Manager state', | |
3492 event, this.watchedDirectoryUrl_); | |
3493 } | |
3494 chrome.fileBrowserPrivate.removeFileWatch(this.watchedDirectoryUrl_, | |
3495 function(result) { | |
3496 if (!result) { | |
3497 console.log('Failed to remove file watch'); | |
3498 } | |
3499 }); | |
3500 this.watchedDirectoryUrl_ = null; | |
3501 } | |
3502 | |
3503 if (event.newDirEntry.fullPath != '/' && !event.newDirEntry.unmounted) { | |
3504 this.watchedDirectoryUrl_ = event.newDirEntry.toURL(); | |
3505 chrome.fileBrowserPrivate.addFileWatch(this.watchedDirectoryUrl_, | |
3506 function(result) { | |
3507 if (!result) { | |
3508 console.log('Failed to add file watch'); | |
3509 this.watchedDirectoryUrl_ = null; | |
3510 } | |
3511 }.bind(this)); | |
3512 } | |
3513 | |
3514 if (event.newDirEntry.unmounted) | |
3515 this.dialogContainer_.setAttribute('unmounted', true); | |
3516 else { | |
3517 this.dialogContainer_.removeAttribute('unmounted'); | |
3518 // Need to resize explicitly because the list container had display:none. | |
3519 this.onResize_(); | |
3520 } | |
3521 | |
3522 if (this.isOnGData()) { | |
3523 this.dialogContainer_.setAttribute('gdata', true); | |
3524 if (event.newDirEntry.unmounted) { | |
3525 this.initGData_(true /* directory changed */); | |
3526 } | |
3527 } else { | |
3528 this.dialogContainer_.removeAttribute('gdata'); | |
3529 } | |
3530 }; | 3317 }; |
3531 | 3318 |
3532 FileManager.prototype.findListItemForEvent_ = function(event) { | 3319 FileManager.prototype.findListItemForEvent_ = function(event) { |
3533 return this.findListItemForNode_(event.srcElement); | 3320 return this.findListItemForNode_(event.srcElement); |
3534 }; | 3321 }; |
3535 | 3322 |
3536 FileManager.prototype.findListItemForNode_ = function(node) { | 3323 FileManager.prototype.findListItemForNode_ = function(node) { |
3537 var item = this.currentList_.getListItemAncestor(node); | 3324 var item = this.currentList_.getListItemAncestor(node); |
3538 // TODO(serya): list should check that. | 3325 // TODO(serya): list should check that. |
3539 return item && this.currentList_.isItem(item) ? item : null; | 3326 return item && this.currentList_.isItem(item) ? item : null; |
3540 }; | 3327 }; |
3541 | 3328 |
3542 /** | 3329 /** |
3543 * Unload handler for the page. May be called manually for the file picker | 3330 * Unload handler for the page. May be called manually for the file picker |
3544 * dialog, because it closes by calling extension API functions that do not | 3331 * dialog, because it closes by calling extension API functions that do not |
3545 * return. | 3332 * return. |
3546 */ | 3333 */ |
3547 FileManager.prototype.onUnload_ = function() { | 3334 FileManager.prototype.onUnload_ = function() { |
3548 if (this.watchedDirectoryUrl_) { | 3335 this.fileWatcher_.stop(); |
3549 chrome.fileBrowserPrivate.removeFileWatch( | |
3550 this.watchedDirectoryUrl_, | |
3551 function(result) { | |
3552 if (!result) { | |
3553 console.log('Failed to remove file watch'); | |
3554 } | |
3555 }); | |
3556 this.watchedDirectoryUrl_ = null; | |
3557 } | |
3558 }; | |
3559 | |
3560 FileManager.prototype.onFileChanged_ = function(event) { | |
3561 // We receive a lot of events even in folders we are not interested in. | |
3562 if (encodeURI(event.fileUrl) == this.getCurrentDirectoryURL()) | |
3563 this.directoryModel_.rescanLater(); | |
3564 }; | 3336 }; |
3565 | 3337 |
3566 FileManager.prototype.initiateRename_ = function() { | 3338 FileManager.prototype.initiateRename_ = function() { |
3567 var item = this.currentList_.ensureLeadItemExists(); | 3339 var item = this.currentList_.ensureLeadItemExists(); |
3568 if (!item) | 3340 if (!item) |
3569 return; | 3341 return; |
3570 var label = item.querySelector('.filename-label'); | 3342 var label = item.querySelector('.filename-label'); |
3571 var input = this.renameInput_; | 3343 var input = this.renameInput_; |
3572 | 3344 |
3573 input.value = label.textContent; | 3345 input.value = label.textContent; |
(...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4479 | 4251 |
4480 this.directoryModel_.addEventListener('scan-completed', maybeShowBanner); | 4252 this.directoryModel_.addEventListener('scan-completed', maybeShowBanner); |
4481 this.directoryModel_.addEventListener('rescan-completed', maybeShowBanner); | 4253 this.directoryModel_.addEventListener('rescan-completed', maybeShowBanner); |
4482 | 4254 |
4483 var style = this.document_.createElement('link'); | 4255 var style = this.document_.createElement('link'); |
4484 style.rel = 'stylesheet'; | 4256 style.rel = 'stylesheet'; |
4485 style.href = 'css/gdrive_welcome.css'; | 4257 style.href = 'css/gdrive_welcome.css'; |
4486 this.document_.head.appendChild(style); | 4258 this.document_.head.appendChild(style); |
4487 }; | 4259 }; |
4488 })(); | 4260 })(); |
4261 | |
4262 function FileChangeWatcher(directoryModel, volumeManager) { | |
4263 | |
4264 this.dm_ = directoryModel; | |
4265 this.vm_ = volumeManager; | |
4266 | |
4267 this.dm_.addEventListener('directory-changed', | |
4268 this.update_.bind(this)); | |
4269 this.vm_.addEventListener('changed', | |
4270 this.update_.bind(this)); | |
4271 }; | |
OLD | NEW |