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

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

Issue 10310163: Refactoring file manager: moving volume mounting related code to a separate class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Bugfixing Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 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
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 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 201
202 if (parent_path[parent_path.length - 1] != '/') 202 if (parent_path[parent_path.length - 1] != '/')
203 parent_path += '/'; 203 parent_path += '/';
204 204
205 if (child_path[child_path.length - 1] != '/') 205 if (child_path[child_path.length - 1] != '/')
206 child_path += '/'; 206 child_path += '/';
207 207
208 return child_path.indexOf(parent_path) == 0; 208 return child_path.indexOf(parent_path) == 0;
209 } 209 }
210 210
211 /**
212 * Normalizes path not to start with /
213 *
214 * @param {string} path The file path.
215 */
216 function normalizeAbsolutePath(x) {
217 if (x[0] == '/')
218 return x.slice(1);
219 else
220 return x;
221 }
222
223 function removeChildren(element) { 211 function removeChildren(element) {
224 element.textContent = ''; 212 element.textContent = '';
225 } 213 }
226 214
227 // Public statics. 215 // Public statics.
228 216
229 /** 217 /**
230 * List of dialog types. 218 * List of dialog types.
231 * 219 *
232 * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except 220 * Keep this in sync with FileManagerDialog::GetDialogTypeAsString, except
(...skipping 14 matching lines...) Expand all
247 type == FileManager.DialogType.SELECT_SAVEAS_FILE || 235 type == FileManager.DialogType.SELECT_SAVEAS_FILE ||
248 type == FileManager.DialogType.SELECT_OPEN_FILE || 236 type == FileManager.DialogType.SELECT_OPEN_FILE ||
249 type == FileManager.DialogType.SELECT_OPEN_MULTI_FILE; 237 type == FileManager.DialogType.SELECT_OPEN_MULTI_FILE;
250 }; 238 };
251 239
252 FileManager.ListType = { 240 FileManager.ListType = {
253 DETAIL: 'detail', 241 DETAIL: 'detail',
254 THUMBNAIL: 'thumb' 242 THUMBNAIL: 'thumb'
255 }; 243 };
256 244
245 FileManager.FileWatcher = function(fileManager) {
246 FileWatcher.call(this,
247 fileManager.filesystem_.root,
248 fileManager.directoryModel_,
249 fileManager.volumeManager_);
250 this.metadataCache_ = fileManager.metadataCache_;
251
252 this.filesystemChanngeHandler_ =
dgozman 2012/05/16 14:31:46 typo here and below: chaNNge
253 fileManager.updateMetadataInUI_.bind(fileManager, 'filesystem');
254 this.gdataChanngeHandler_ =
255 fileManager.updateMetadataInUI_.bind(fileManager, 'gdata');
256
257 this.filesystemObserverId_ = null;
258 this.gdataObserverId_ = null;
259 };
260
261 FileManager.FileWatcher.prototype.__proto__ = FileWatcher.prototype;
262
263 FileManager.FileWatcher.prototype.changeWatchedEntry = function(entry) {
264 FileWatcher.prototype.changeWatchedEntry.call(this, entry);
265
266 if (this.filesystemObserverId_)
267 this.metadataCache_.removeObserver(this.filesystemObserverId_);
268 if (this.gdataObserverId_)
269 this.metadataCache_.removeObserver(this.gdataObserverId_);
270 this.filesystemObserverId_ = null;
271 this.gdataObserverId_ = null;
272 if (!entry)
273 return;
274
275 this.filesystemObserverId_ = this.metadataCache_.addObserver(
276 entry,
277 MetadataCache.CHILDREN,
278 'filesystem',
279 this.filesystemChanngeHandler_);
280
281 if (DirectoryModel.getRootType(entry.fullPath) ==
282 DirectoryModel.RootType.GDATA) {
283 this.gdataObserverId_ = this.metadataCache_.addObserver(
284 entry,
285 MetadataCache.CHILDREN,
286 'gdata',
287 this.gdataChanngeHandler_);
288 }
289 };
290
257 /** 291 /**
258 * Load translated strings. 292 * Load translated strings.
259 */ 293 */
260 FileManager.initStrings = function(callback) { 294 FileManager.initStrings = function(callback) {
261 chrome.fileBrowserPrivate.getStrings(function(strings) { 295 chrome.fileBrowserPrivate.getStrings(function(strings) {
262 localStrings = new LocalStrings(strings); 296 localStrings = new LocalStrings(strings);
263 if (callback) 297 if (callback)
264 callback(); 298 callback();
265 }); 299 });
266 }; 300 };
(...skipping 10 matching lines...) Expand all
277 util.UNITS = [str('SIZE_KB'), 311 util.UNITS = [str('SIZE_KB'),
278 str('SIZE_MB'), 312 str('SIZE_MB'),
279 str('SIZE_GB'), 313 str('SIZE_GB'),
280 str('SIZE_TB'), 314 str('SIZE_TB'),
281 str('SIZE_PB')]; 315 str('SIZE_PB')];
282 316
283 metrics.startInterval('Load.FileSystem'); 317 metrics.startInterval('Load.FileSystem');
284 318
285 var self = this; 319 var self = this;
286 320
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) { 321 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) {
299 metrics.recordInterval('Load.FileSystem'); 322 metrics.recordInterval('Load.FileSystem');
300 self.filesystem_ = filesystem; 323 self.filesystem_ = filesystem;
301 onDone(); 324 self.init_();
302 }); 325 });
303 }; 326 };
304 327
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 /** 328 /**
313 * Continue initializing the file manager after resolving roots. 329 * Continue initializing the file manager after resolving roots.
314 */ 330 */
315 FileManager.prototype.init_ = function() { 331 FileManager.prototype.init_ = function() {
316 metrics.startInterval('Load.DOM'); 332 metrics.startInterval('Load.DOM');
317 this.initCommands_(); 333 this.initCommands_();
318 334
319 this.metadataCache_ = MetadataCache.createFull(); 335 this.metadataCache_ = MetadataCache.createFull();
320 336
321 this.shortDateFormatter_ = 337 this.shortDateFormatter_ =
(...skipping 11 matching lines...) Expand all
333 349
334 this.table_.startBatchUpdates(); 350 this.table_.startBatchUpdates();
335 this.grid_.startBatchUpdates(); 351 this.grid_.startBatchUpdates();
336 352
337 this.initFileList_(); 353 this.initFileList_();
338 this.initDialogs_(); 354 this.initDialogs_();
339 355
340 window.addEventListener('popstate', this.onPopState_.bind(this)); 356 window.addEventListener('popstate', this.onPopState_.bind(this));
341 window.addEventListener('unload', this.onUnload_.bind(this)); 357 window.addEventListener('unload', this.onUnload_.bind(this));
342 358
343 this.directoryModel_.addEventListener('directory-changed', 359 var dm = this.directoryModel_;
360 dm.addEventListener('directory-changed',
344 this.onDirectoryChanged_.bind(this)); 361 this.onDirectoryChanged_.bind(this));
345 var self = this; 362 var self = this;
346 this.directoryModel_.addEventListener('begin-update-files', function() { 363 dm.addEventListener('begin-update-files', function() {
347 self.currentList_.startBatchUpdates(); 364 self.currentList_.startBatchUpdates();
348 }); 365 });
349 this.directoryModel_.addEventListener('end-update-files', function() { 366 dm.addEventListener('end-update-files', function() {
350 self.restoreItemBeingRenamed_(); 367 self.restoreItemBeingRenamed_();
351 self.currentList_.endBatchUpdates(); 368 self.currentList_.endBatchUpdates();
352 }); 369 });
353 this.directoryModel_.addEventListener('scan-started', 370 dm.addEventListener('scan-started', this.showSpinnerLater_.bind(this));
354 this.showSpinnerLater_.bind(this)); 371 dm.addEventListener('scan-completed', this.showSpinner_.bind(this, false));
355 this.directoryModel_.addEventListener('scan-completed', 372 dm.addEventListener('scan-completed',
356 this.showSpinner_.bind(this, false)); 373 this.refreshCurrentDirectoryMetadata_.bind(this));
357 this.directoryModel_.addEventListener('scan-completed', 374 dm.addEventListener('rescan-completed',
358 this.refreshCurrentDirectoryMetadata_.bind(this)); 375 this.refreshCurrentDirectoryMetadata_.bind(this));
359 this.directoryModel_.addEventListener('rescan-completed',
360 this.refreshCurrentDirectoryMetadata_.bind(this));
361 this.addEventListener('selection-summarized', 376 this.addEventListener('selection-summarized',
362 this.onSelectionSummarized_.bind(this)); 377 this.onSelectionSummarized_.bind(this));
363 378
364 // The list of archives requested to mount. We will show contents once 379 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; 380 this.networkConnectionState_ = null;
375 var queryNetworkConnectionState = function() { 381 var queryNetworkConnectionState = function() {
376 chrome.fileBrowserPrivate.getNetworkConnectionState( 382 chrome.fileBrowserPrivate.getNetworkConnectionState(
377 this.onNetworkConnectionChanged_.bind(this)); 383 this.onNetworkConnectionChanged_.bind(this));
378 }.bind(this); 384 }.bind(this);
379 queryNetworkConnectionState(); 385 queryNetworkConnectionState();
380 chrome.fileBrowserPrivate.onNetworkConnectionChanged. 386 chrome.fileBrowserPrivate.onNetworkConnectionChanged.
381 addListener(queryNetworkConnectionState); 387 addListener(queryNetworkConnectionState);
382 388
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
406 this.summarizeSelection_(); 389 this.summarizeSelection_();
407 390
408 var sortField = 391 var sortField =
409 window.localStorage['sort-field-' + this.dialogType_] || 392 window.localStorage['sort-field-' + this.dialogType_] ||
410 'modificationTime'; 393 'modificationTime';
411 var sortDirection = 394 var sortDirection =
412 window.localStorage['sort-direction-' + this.dialogType_] || 'desc'; 395 window.localStorage['sort-direction-' + this.dialogType_] || 'desc';
413 this.directoryModel_.sortFileList(sortField, sortDirection); 396 this.directoryModel_.sortFileList(sortField, sortDirection);
414 397
415 this.refocus(); 398 this.refocus();
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
509 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); 492 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input');
510 this.taskItems_ = this.dialogDom_.querySelector('#tasks'); 493 this.taskItems_ = this.dialogDom_.querySelector('#tasks');
511 this.okButton_ = this.dialogDom_.querySelector('.ok'); 494 this.okButton_ = this.dialogDom_.querySelector('.ok');
512 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); 495 this.cancelButton_ = this.dialogDom_.querySelector('.cancel');
513 this.deleteButton_ = this.dialogDom_.querySelector('#delete-button'); 496 this.deleteButton_ = this.dialogDom_.querySelector('#delete-button');
514 this.table_ = this.dialogDom_.querySelector('.detail-table'); 497 this.table_ = this.dialogDom_.querySelector('.detail-table');
515 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid'); 498 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid');
516 this.spinner_ = this.dialogDom_.querySelector('.spinner'); 499 this.spinner_ = this.dialogDom_.querySelector('.spinner');
517 this.showSpinner_(false); 500 this.showSpinner_(false);
518 this.butter_ = this.dialogDom_.querySelector('.butter-bar'); 501 this.butter_ = this.dialogDom_.querySelector('.butter-bar');
519 this.unmountedPanel_ = this.dialogDom_.querySelector('.unmounted-panel');
520 502
521 cr.ui.decorate('#gdata-settings', cr.ui.MenuButton); 503 cr.ui.decorate('#gdata-settings', cr.ui.MenuButton);
522 cr.ui.Table.decorate(this.table_); 504 cr.ui.Table.decorate(this.table_);
523 cr.ui.Grid.decorate(this.grid_); 505 cr.ui.Grid.decorate(this.grid_);
524 506
525 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); 507 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this));
526 // Disable the default browser context menu. 508 // Disable the default browser context menu.
527 this.document_.addEventListener('contextmenu', 509 this.document_.addEventListener('contextmenu',
528 function(e) { e.preventDefault() }); 510 function(e) { e.preventDefault() });
529 511
(...skipping 29 matching lines...) Expand all
559 541
560 this.decorateSplitter( 542 this.decorateSplitter(
561 this.dialogDom_.querySelector('div.sidebar-splitter')); 543 this.dialogDom_.querySelector('div.sidebar-splitter'));
562 544
563 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); 545 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container');
564 this.dialogDom_.querySelector('#detail-view').addEventListener( 546 this.dialogDom_.querySelector('#detail-view').addEventListener(
565 'click', this.onDetailViewButtonClick_.bind(this)); 547 'click', this.onDetailViewButtonClick_.bind(this));
566 this.dialogDom_.querySelector('#thumbnail-view').addEventListener( 548 this.dialogDom_.querySelector('#thumbnail-view').addEventListener(
567 'click', this.onThumbnailViewButtonClick_.bind(this)); 549 'click', this.onThumbnailViewButtonClick_.bind(this));
568 550
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'); 551 this.syncButton = this.dialogDom_.querySelector('#gdata-sync-settings');
575 this.syncButton.addEventListener('click', this.onGDataPrefClick_.bind( 552 this.syncButton.addEventListener('click', this.onGDataPrefClick_.bind(
576 this, 'cellularDisabled', false /* not inverted */)); 553 this, 'cellularDisabled', false /* not inverted */));
577 554
578 this.hostedButton = this.dialogDom_.querySelector('#gdata-hosted-settings'); 555 this.hostedButton = this.dialogDom_.querySelector('#gdata-hosted-settings');
579 this.hostedButton.addEventListener('click', this.onGDataPrefClick_.bind( 556 this.hostedButton.addEventListener('click', this.onGDataPrefClick_.bind(
580 this, 'hostedFilesDisabled', true /* inverted */)); 557 this, 'hostedFilesDisabled', true /* inverted */));
581 558
582 this.gdataPreferences_ = null; 559 this.gdataPreferences_ = null;
583 var queryGDataPreferences = function() { 560 var queryGDataPreferences = function() {
584 chrome.fileBrowserPrivate.getGDataPreferences( 561 chrome.fileBrowserPrivate.getGDataPreferences(
585 this.onGDataPreferencesChanged_.bind(this)); 562 this.onGDataPreferencesChanged_.bind(this));
586 }.bind(this); 563 }.bind(this);
587 queryGDataPreferences(); 564 queryGDataPreferences();
588 chrome.fileBrowserPrivate.onGDataPreferencesChanged. 565 // TODO(serya): uncomment
589 addListener(queryGDataPreferences); 566 //chrome.fileBrowserPrivate.onGDataPreferencesChanged.
567 // addListener(queryGDataPreferences);
590 568
591 cr.ui.ComboButton.decorate(this.taskItems_); 569 cr.ui.ComboButton.decorate(this.taskItems_);
592 this.taskItems_.addEventListener('select', 570 this.taskItems_.addEventListener('select',
593 this.onTaskItemClicked_.bind(this)); 571 this.onTaskItemClicked_.bind(this));
594 572
595 this.dialogDom_.ownerDocument.defaultView.addEventListener( 573 this.dialogDom_.ownerDocument.defaultView.addEventListener(
596 'resize', this.onResize_.bind(this)); 574 'resize', this.onResize_.bind(this));
597 575
598 if (str('ASH') == '1') 576 if (str('ASH') == '1')
599 this.dialogDom_.setAttribute('ash', 'true'); 577 this.dialogDom_.setAttribute('ash', 'true');
(...skipping 19 matching lines...) Expand all
619 597
620 var sigleSelection = 598 var sigleSelection =
621 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || 599 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE ||
622 this.dialogType_ == FileManager.DialogType.SELECT_FOLDER || 600 this.dialogType_ == FileManager.DialogType.SELECT_FOLDER ||
623 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE; 601 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE;
624 602
625 this.directoryModel_ = new DirectoryModel( 603 this.directoryModel_ = new DirectoryModel(
626 this.filesystem_.root, 604 this.filesystem_.root,
627 sigleSelection, 605 sigleSelection,
628 FileManager.isGDataEnabled(), 606 FileManager.isGDataEnabled(),
629 this.metadataCache_); 607 this.metadataCache_,
608 this.volumeManager_);
609
610 this.fileWatcher_ = new FileManager.FileWatcher(this);
611 this.fileWatcher_.start();
630 612
631 if (FileManager.isGDataEnabled()) 613 if (FileManager.isGDataEnabled())
632 this.initGDataWelcomeBanners_(); 614 this.initGDataWelcomeBanners_();
633 615
634 var dataModel = this.directoryModel_.getFileList(); 616 var dataModel = this.directoryModel_.getFileList();
635 var collator = this.collator_; 617 var collator = this.collator_;
636 // TODO(dgozman): refactor comparison functions together with 618 // TODO(dgozman): refactor comparison functions together with
637 // render/update/display. 619 // render/update/display.
638 dataModel.setCompareFunction('name', function(a, b) { 620 dataModel.setCompareFunction('name', function(a, b) {
639 return collator.compare(a.name, b.name); 621 return collator.compare(a.name, b.name);
(...skipping 17 matching lines...) Expand all
657 this.initGrid_(); 639 this.initGrid_();
658 this.initRootsList_(); 640 this.initRootsList_();
659 641
660 var listType = FileManager.ListType.DETAIL; 642 var listType = FileManager.ListType.DETAIL;
661 if (FileManager.DialogType.isModal(this.dialogType_)) 643 if (FileManager.DialogType.isModal(this.dialogType_))
662 listType = window.localStorage['listType-' + this.dialogType_] || 644 listType = window.localStorage['listType-' + this.dialogType_] ||
663 FileManager.ListType.DETAIL; 645 FileManager.ListType.DETAIL;
664 this.setListType(listType); 646 this.setListType(listType);
665 647
666 this.textSearchState_ = {text: '', date: new Date()}; 648 this.textSearchState_ = {text: '', date: new Date()};
649
650 this.volumeManager_.addEventListener('gdata-status-changed',
651 this.updateGDataStatus_.bind(this, 'status-change'));
667 }; 652 };
668 653
669 FileManager.prototype.initRootsList_ = function() { 654 FileManager.prototype.initRootsList_ = function() {
670 this.rootsList_ = this.dialogDom_.querySelector('#roots-list'); 655 this.rootsList_ = this.dialogDom_.querySelector('#roots-list');
671 cr.ui.List.decorate(this.rootsList_); 656 cr.ui.List.decorate(this.rootsList_);
672 this.rootsList_.startBatchUpdates();
673 657
674 var self = this; 658 var self = this;
675 this.rootsList_.itemConstructor = function(entry) { 659 this.rootsList_.itemConstructor = function(entry) {
676 return self.renderRoot_(entry); 660 return self.renderRoot_(entry);
677 }; 661 };
678 662
679 this.rootsList_.selectionModel = 663 this.rootsList_.selectionModel =
680 this.directoryModel_.getRootsListSelectionModel(); 664 this.directoryModel_.getRootsListSelectionModel();
681 665
682 // TODO(dgozman): add "Add a drive" item. 666 // TODO(dgozman): add "Add a drive" item.
683 this.rootsList_.dataModel = this.directoryModel_.getRootsList(); 667 this.rootsList_.dataModel = this.directoryModel_.getRootsList();
684 this.directoryModel_.updateRoots(function() {
685 self.rootsList_.endBatchUpdates();
686 }, false);
687 }; 668 };
688 669
689 /** 670 FileManager.prototype.updateGDataStatus_ = function(reason) {
690 * @param {boolean} dirChanged True if we just changed to GData directory, 671 var node = this.dialogContainer_;
691 * False if "Retry" button clicked. 672 if (this.isOnGData()) {
692 */ 673 var status = this.volumeManager_.getGDataStatus();
693 FileManager.prototype.initGData_ = function(dirChanged) { 674 if (status == VolumeManager.GDataStatus.MOUNTING ||
694 this.initGDataUnmountedPanel_(); 675 status == VolumeManager.GDataStatus.ERROR) {
695 676 this.initGDataUnmountedPanel_();
696 this.unmountedPanel_.removeAttribute('error'); 677 var retryButton = this.document_.querySelector(
697 if (dirChanged) { 678 '#unmounted-panel button.retry');
698 // When changing to GData directory we want to see a clear panel. 679 if (status == VolumeManager.GDataStatus.ERROR)
699 this.unmountedPanel_.removeAttribute('retry'); 680 retryButton.hidden = false;
700 if (this.gdataLoadingTimer_) { // Show immediately if already loading. 681 else if (reason == 'directory-change')
701 this.unmountedPanel_.setAttribute('loading', true); 682 retryButton.hidden = 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 } 683 }
684 node.setAttribute('gdata', status);
710 } else { 685 } else {
711 // When retrying we do not hide "Retry" and "Learn more". 686 node.removeAttribute('gdata');
712 this.unmountedPanel_.setAttribute('loading', true);
713 } 687 }
714 688 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 }; 689 };
749 690
750 FileManager.prototype.initGDataUnmountedPanel_ = function() { 691 FileManager.prototype.initGDataUnmountedPanel_ = function() {
751 if (this.unmountedPanel_.firstElementChild) 692 var panel = this.document_.querySelector('#unmounted-panel');
693 if (panel.firstElementChild)
752 return; 694 return;
753 695
754 var loading = this.document_.createElement('div'); 696 function create(tag, className) {
755 loading.className = 'gdata loading'; 697 var div = panel.ownerDocument.createElement(tag);
756 loading.textContent = str('GDATA_LOADING'); 698 div.className = className;
757 this.unmountedPanel_.appendChild(loading); 699 return div;
700 }
758 701
759 var spinnerBox = this.document_.createElement('div'); 702 function append(tag, className, opt_textContent) {
760 spinnerBox.className = 'spinner-box'; 703 var div = create(tag, className);
761 loading.appendChild(spinnerBox); 704 div.textContent = opt_textContent || '';
705 panel.appendChild(div);
706 return div;
707 }
762 708
763 var spinner = this.document_.createElement('div'); 709 append('div', 'gdata loading', str('GDATA_LOADING'));
764 spinner.className = 'spinner'; 710 append('div', 'spinner-box').appendChild(create('div', 'spinner'));
765 spinnerBox.appendChild(spinner); 711 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( 712 chrome.fileBrowserPrivate.onDocumentFeedFetched.addListener(
772 function(fileCount) { 713 function(fileCount) {
773 progress.textContent = strf('GDATA_LOADING_PROGRESS', fileCount); 714 progress.textContent = strf('GDATA_LOADING_PROGRESS', fileCount);
774 }); 715 });
775 716
776 var error = this.document_.createElement('div'); 717 append('div', 'gdata error', strf('GDATA_CANNOT_REACH',
777 error.className = 'gdata error'; 718 str('GDATA_PRODUCT_NAME')));
778 error.textContent = strf('GDATA_CANNOT_REACH', str('GDATA_PRODUCT_NAME'));
779 this.unmountedPanel_.appendChild(error);
780 719
781 var retry = this.document_.createElement('button'); 720 append('button', 'gdata retry', str('GDATA_RETRY'));
782 retry.className = 'gdata retry'; 721 // 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 722
787 var learnMore = this.document_.createElement('div'); 723 append('div', 'gdata learn-more plain-link', str('GDATA_LEARN_MORE')).
788 learnMore.className = 'gdata learn-more plain-link'; 724 onclick = this.onExternalLinkClick_.bind(this,
789 learnMore.textContent = str('GDATA_LEARN_MORE'); 725 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 }; 726 };
794 727
795 FileManager.prototype.onDataModelSplice_ = function(event) { 728 FileManager.prototype.onDataModelSplice_ = function(event) {
796 var checkbox = this.document_.querySelector('#select-all-checkbox'); 729 var checkbox = this.document_.querySelector('#select-all-checkbox');
797 if (checkbox) 730 if (checkbox)
798 this.updateSelectAllCheckboxState_(checkbox); 731 this.updateSelectAllCheckboxState_(checkbox);
799 }; 732 };
800 733
801 FileManager.prototype.onDataModelPermuted_ = function(event) { 734 FileManager.prototype.onDataModelPermuted_ = function(event) {
802 var sortStatus = this.directoryModel_.getFileList().sortStatus; 735 var sortStatus = this.directoryModel_.getFileList().sortStatus;
(...skipping 530 matching lines...) Expand 10 before | Expand all | Expand 10 after
1333 1266
1334 case 'delete': 1267 case 'delete':
1335 this.deleteEntries(this.selection.entries); 1268 this.deleteEntries(this.selection.entries);
1336 return; 1269 return;
1337 1270
1338 case 'newfolder': 1271 case 'newfolder':
1339 this.onNewFolderCommand_(event); 1272 this.onNewFolderCommand_(event);
1340 return; 1273 return;
1341 1274
1342 case 'unmount': 1275 case 'unmount':
1343 this.unmountVolume_(this.directoryModel_.getCurrentRootDirEntry()); 1276 this.unmountVolume_(
1277 this.directoryModel_.getCurrentRootDirEntry());
1344 return; 1278 return;
1345 1279
1346 case 'format': 1280 case 'format':
1347 var entry = this.directoryModel_.getCurrentRootDirEntry(); 1281 var entry = this.directoryModel_.getCurrentRootDirEntry();
1348 this.confirm.show(str('FORMATTING_WARNING'), function() { 1282 this.confirm.show(str('FORMATTING_WARNING'), function() {
1349 chrome.fileBrowserPrivate.formatDevice(entry.toURL()); 1283 chrome.fileBrowserPrivate.formatDevice(entry.toURL());
1350 }); 1284 });
1351 1285
1352 return; 1286 return;
1353 } 1287 }
1354 }; 1288 };
1355 1289
1356 /** 1290 /**
1357 * Respond to the back and forward buttons. 1291 * Respond to the back and forward buttons.
1358 */ 1292 */
1359 FileManager.prototype.onPopState_ = function(event) { 1293 FileManager.prototype.onPopState_ = function(event) {
1360 this.closeFilePopup_(); 1294 this.closeFilePopup_();
1361 // Nothing left to do if the current directory is not changing. This happens 1295 // Nothing left to do if the current directory is not changing. This happens
1362 // if we are exiting the Gallery. 1296 // if we are exiting the Gallery.
1363 if (this.getPathFromUrlOrParams_() == 1297 if (this.getPathFromUrlOrParams_() ==
1364 this.directoryModel_.getCurrentDirEntry().fullPath) 1298 this.directoryModel_.getCurrentDirEntry().fullPath)
1365 return; 1299 return;
1366 this.setupCurrentDirectory_(true /* invokeHandler */); 1300 this.setupCurrentDirectory_(false /* page loading */);
1367 }; 1301 };
1368 1302
1369 FileManager.prototype.requestResize_ = function(timeout) { 1303 FileManager.prototype.requestResize_ = function(timeout) {
1370 setTimeout(this.onResize_.bind(this), timeout || 0); 1304 setTimeout(this.onResize_.bind(this), timeout || 0);
1371 }; 1305 };
1372 1306
1373 /** 1307 /**
1374 * Resize details and thumb views to fit the new window size. 1308 * Resize details and thumb views to fit the new window size.
1375 */ 1309 */
1376 FileManager.prototype.onResize_ = function() { 1310 FileManager.prototype.onResize_ = function() {
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1410 }; 1344 };
1411 1345
1412 /** 1346 /**
1413 * Restores current directory and may be a selected item after page load (or 1347 * 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 1348 * 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 1349 * 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. 1350 * will be restored. defaultPath primarily is used with save/open dialogs.
1417 * Default path may also contain a file name. Freshly opened file manager 1351 * Default path may also contain a file name. Freshly opened file manager
1418 * window has neither. 1352 * window has neither.
1419 * 1353 *
1420 * @param {boolean} invokeHandler Whether to invoke the default handler on 1354 * @param {boolean} pageLoading True if pase is loading,
1421 * the selected file. 1355 false if popping state.
1422 * @param {boolean} opt_blankWhileOpeningAFile Whether to show fade over
1423 * the file manager.
1424 */ 1356 */
1425 FileManager.prototype.setupCurrentDirectory_ = 1357 FileManager.prototype.setupCurrentDirectory_ = function(pageLoading) {
1426 function(invokeHandler, opt_blankWhileOpeningAFile) {
1427 var path = this.getPathFromUrlOrParams_(); 1358 var path = this.getPathFromUrlOrParams_();
1428 1359
1429 if (!path) { 1360 if (!path) {
1430 this.directoryModel_.setupDefaultPath(); 1361 this.directoryModel_.setupDefaultPath();
1431 return; 1362 return;
1432 } 1363 }
1433 1364
1365 if (DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA) {
1366 if (!FileManager.isGDataEnabled()) {
1367 this.directoryModel_.setupDefaultPath();
1368 return;
1369 }
1370
1371 // Reflect immediatelly in the UI we are on GData and display
1372 // mounting UI.
1373 this.directoryModel_.setupPath('/' + DirectoryModel.GDATA_DIRECTORY);
1374
1375 var tracker = this.directoryModel_.createDirectoryChangeTracker();
1376 // Expected finish of setupPath to GData.
1377 tracker.exceptInitialChange = true;
1378 tracker.start();
1379 this.volumeManager_.mountGData(function() {
1380 tracker.stop();
1381 if (!tracker.hasChanged) {
1382 this.finishSetupCurrentDirectory_(path, pageLoading);
1383 }
1384 }.bind(this), function(error) {
1385 tracker.stop();
1386 });
1387 } else {
1388 this.finishSetupCurrentDirectory_(path, pageLoading);
1389 }
1390 };
1391
1392 FileManager.prototype.finishSetupCurrentDirectory_ = function(
1393 path, pageLoading) {
1394 var invokeHandler = pageLoading && !this.params_.selectOnly;
1434 // In the FULL_PAGE mode if the hash path points to a file we might have 1395 // In the FULL_PAGE mode if the hash path points to a file we might have
1435 // to invoke a task after selecting it. 1396 // to invoke a task after selecting it.
1436 // If the file path is in params_ we only want to select the file. 1397 // If the file path is in params_ we only want to select the file.
1437 if (invokeHandler && location.hash && 1398 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE &&
1438 this.dialogType_ == FileManager.DialogType.FULL_PAGE) { 1399 location.hash && invokeHandler) {
1439 // To prevent the file list flickering for a moment before the action 1400 // To prevent the file list flickering for a moment before the action
1440 // is executed we hide it under a white div. 1401 // is executed we hide it under a white div.
1441 var shade; 1402 var shade;
1442 if (opt_blankWhileOpeningAFile) { 1403 if (pageLoading) {
1443 shade = this.document_.createElement('div'); 1404 shade = this.document_.createElement('div');
1444 shade.className = 'overlay-pane'; 1405 shade.className = 'overlay-pane';
1445 shade.style.backgroundColor = 'white'; 1406 shade.style.backgroundColor = 'white';
1446 this.document_.body.appendChild(shade); 1407 this.document_.body.appendChild(shade);
1447 } 1408 }
1448 function removeShade() { 1409 function removeShade() {
1449 if (shade) 1410 if (shade)
1450 shade.parentNode.removeChild(shade); 1411 shade.parentNode.removeChild(shade);
1451 } 1412 }
1452 1413
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after
1768 } 1729 }
1769 }; 1730 };
1770 li.addEventListener('mousedown', handleClick); 1731 li.addEventListener('mousedown', handleClick);
1771 li.addEventListener(cr.ui.TouchHandler.EventType.TOUCH_START, handleClick); 1732 li.addEventListener(cr.ui.TouchHandler.EventType.TOUCH_START, handleClick);
1772 1733
1773 var rootType = DirectoryModel.getRootType(entry.fullPath); 1734 var rootType = DirectoryModel.getRootType(entry.fullPath);
1774 1735
1775 var div = this.document_.createElement('div'); 1736 var div = this.document_.createElement('div');
1776 div.className = 'root-label'; 1737 div.className = 'root-label';
1777 1738
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); 1739 div.textContent = this.getRootLabel_(entry.fullPath);
1791 li.appendChild(div); 1740 li.appendChild(div);
1792 1741
1793 if (rootType == DirectoryModel.RootType.ARCHIVE || 1742 if (rootType == DirectoryModel.RootType.ARCHIVE ||
1794 rootType == DirectoryModel.RootType.REMOVABLE) { 1743 rootType == DirectoryModel.RootType.REMOVABLE) {
1795 if (entry.unmounting) { 1744 var eject = this.document_.createElement('div');
1796 li.setAttribute('disabled', 'disabled'); 1745 eject.className = 'root-eject';
1797 } else { 1746 eject.addEventListener('click', function(event) {
1798 var eject = this.document_.createElement('div'); 1747 event.stopPropagation();
1799 eject.className = 'root-eject'; 1748 this.unmountVolume_(entry);
1800 eject.addEventListener('click', function(event) { 1749 }.bind(this));
1801 event.stopPropagation(); 1750 // Block other mouse handlers.
1802 this.unmountVolume_(entry); 1751 eject.addEventListener('mouseup', function(e) { e.stopPropagation() });
1803 }.bind(this)); 1752 eject.addEventListener('mousedown', function(e) { e.stopPropagation() });
1804 // Block other mouse handlers. 1753 li.appendChild(eject);
1805 eject.addEventListener('mouseup', function(e) { e.stopPropagation() });
1806 eject.addEventListener('mousedown', function(e) { e.stopPropagation() }) ;
1807 li.appendChild(eject);
1808 1754
1809 cr.ui.contextMenuHandler.setContextMenu(li, this.rootsContextMenu_); 1755 cr.ui.contextMenuHandler.setContextMenu(li, this.rootsContextMenu_);
1810 }
1811 } 1756 }
1812 1757
1813 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); 1758 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR);
1814 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); 1759 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR);
1760
1761 var icon = rootType;
1762 var mountCondition = this.volumeManager_.getMountCondition(entry.fullPath);
1763
1764 if (mountCondition == 'unknown_filesystem' ||
1765 mountCondition == 'unsupported_filesystem') {
1766 icon = 'unreadable';
1767 }
1768 div.setAttribute('icon', icon);
1769
1815 return li; 1770 return li;
1816 }; 1771 };
1817 1772
1818 /** 1773 /**
1819 * Unmounts device. 1774 * Unmounts device.
1820 * @param {Entry} entry The entry to unmount. 1775 * @param {Entry} entry The entry to unmount.
1821 */ 1776 */
1822 FileManager.prototype.unmountVolume_ = function(entry) { 1777 FileManager.prototype.unmountVolume_ = function(entry) {
1823 this.directoryModel_.prepareUnmount(entry.fullPath); 1778 listItem = this.rootsList_.getListItem(entry);
1824 this.unmountRequests_.push(entry.fullPath); 1779 listItem && listItem.setAttribute('disabled');
dgozman 2012/05/16 14:31:46 Don't like this syntax.
1825 chrome.fileBrowserPrivate.removeMount(entry.toURL()); 1780 var self = this;
1781 this.volumeManager_.unmount(entry.fullPath, function() {},
1782 function(error) {
1783 listItem && listItem.removeAttribute('disabled');
1784 self.alert.show(strf('UNMOUNT_FAILED', error.message));
1785 });
1826 }; 1786 };
1827 1787
1828 FileManager.prototype.updateGDataStyle_ = function( 1788 FileManager.prototype.updateGDataStyle_ = function(
1829 listItem, entry, gdata) { 1789 listItem, entry, gdata) {
1830 if (!this.isOnGData() || !gdata) 1790 if (!this.isOnGData() || !gdata)
1831 return; 1791 return;
1832 1792
1833 if (!entry.isDirectory) { 1793 if (!entry.isDirectory) {
1834 if (!gdata.availableOffline) 1794 if (!gdata.availableOffline)
1835 listItem.classList.add('dim-offline'); 1795 listItem.classList.add('dim-offline');
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
2193 selection.bytes += filesystem.size; 2153 selection.bytes += filesystem.size;
2194 } 2154 }
2195 } 2155 }
2196 2156
2197 this.dispatchEvent(new cr.Event('selection-summarized')); 2157 this.dispatchEvent(new cr.Event('selection-summarized'));
2198 }.bind(this)); 2158 }.bind(this));
2199 2159
2200 if (this.isOnGData()) { 2160 if (this.isOnGData()) {
2201 this.metadataCache_.get(selection.urls, 'gdata', function(props) { 2161 this.metadataCache_.get(selection.urls, 'gdata', function(props) {
2202 selection.allGDataFilesPresent = 2162 selection.allGDataFilesPresent =
2203 props.filter(function(p) {return !p.availableOffline}).length == 0; 2163 props.filter(function(p) {return p && !p.availableOffline}).length = = 0;
dgozman 2012/05/16 14:31:46 - long line - this actually should be |!(p && p.av
2204 this.updateOkButton_(); 2164 this.updateOkButton_();
2205 }.bind(this)); 2165 }.bind(this));
2206 } 2166 }
2207 }; 2167 };
2208 2168
2209 /** 2169 /**
2210 * Check if all the files in the current selection are available. The only 2170 * 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 2171 * case when files might be not available is when the selection contains
2212 * uncached GData files and the browser is offline. 2172 * uncached GData files and the browser is offline.
2213 * @return {boolean} True if all files in the current selection are 2173 * @return {boolean} True if all files in the current selection are
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
2625 }; 2585 };
2626 2586
2627 FileManager.prototype.isOffline = function() { 2587 FileManager.prototype.isOffline = function() {
2628 return this.networkConnectionState_ && !this.networkConnectionState_.online; 2588 return this.networkConnectionState_ && !this.networkConnectionState_.online;
2629 }; 2589 };
2630 2590
2631 FileManager.prototype.isOnReadonlyDirectory = function() { 2591 FileManager.prototype.isOnReadonlyDirectory = function() {
2632 return this.directoryModel_.isReadOnly(); 2592 return this.directoryModel_.isReadOnly();
2633 }; 2593 };
2634 2594
2635 /** 2595 // TODO(serya): close tab on unmount.
2636 * Event handler called when some volume was mounted or unmouted. 2596 FileManager.prototype.onVolumeUnmounted_ = function(event) {
2637 */ 2597 if (event.mountPath == dm.getCurrentRootPath()) {
2638 FileManager.prototype.onMountCompleted_ = function(event) { 2598 if (this.params_.mountTriggered && !event.requested) {
2639 var changeDirectoryTo = null; 2599 // TODO(serya): What if 2 USB sticks plugged?
2640 2600 chrome.tabs.getCurrent(function(tab) {
2641 if (event && event.mountType == 'gdata') { 2601 chrome.tabs.remove(tab.id);
2642 var mounted = (event.eventType == 'mount'); 2602 });
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 } 2603 }
2676 } 2604 }
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 }; 2605 };
2735 2606
2736 /** 2607 /**
2737 * Event handler called when some internal task should be executed. 2608 * Event handler called when some internal task should be executed.
2738 */ 2609 */
2739 FileManager.prototype.onFileTaskExecute_ = function(id, urls) { 2610 FileManager.prototype.onFileTaskExecute_ = function(id, urls) {
2740 if (id == 'play') { 2611 if (id == 'play') {
2741 var position = 0; 2612 var position = 0;
2742 if (urls.length == 1) { 2613 if (urls.length == 1) {
2743 // If just a single audio file is selected pass along every audio file 2614 // If just a single audio file is selected pass along every audio file
2744 // in the directory. 2615 // in the directory.
2745 var selectedUrl = urls[0]; 2616 var selectedUrl = urls[0];
2746 urls = this.getAllUrlsInCurrentDirectory_().filter(FileType.isAudio); 2617 urls = this.getAllUrlsInCurrentDirectory_().filter(FileType.isAudio);
2747 position = urls.indexOf(selectedUrl); 2618 position = urls.indexOf(selectedUrl);
2748 } 2619 }
2749 chrome.mediaPlayerPrivate.play(urls, position); 2620 chrome.mediaPlayerPrivate.play(urls, position);
2750 } else if (id == 'mount-archive') { 2621 } else if (id == 'mount-archive') {
2751 var self = this; 2622 var self = this;
2623 var tracker = this.directoryModel_.createDirectoryChangeTracker();
2624 tracker.start();
2752 this.resolveSelectResults_(urls, function(urls) { 2625 this.resolveSelectResults_(urls, function(urls) {
2753 for (var index = 0; index < urls.length; ++index) { 2626 for (var index = 0; index < urls.length; ++index) {
2754 // Url in MountCompleted event won't be escaped, so let's make sure 2627 var path = /^filesystem:[\w-]*:\/\/[\w]*\/external(\/.*)$/.
2755 // we don't use escaped one in mountRequests_. 2628 exec(urls[index])[1];
2756 var unescapedUrl = unescape(urls[index]); 2629 if (!path)
2757 chrome.fileBrowserPrivate.addMount(unescapedUrl, 'file', {}, 2630 continue;
2758 function(sourcePath) { 2631 path = decodeURIComponent(path);
2759 self.mountRequests_.push(sourcePath); 2632 self.volumeManager_.mountArchive(path, function(mountPath) {
2633 console.log('Mounted at: ', mountPath);
2634 tracker.stop();
2635 if (!tracker.hasChanged)
2636 self.directoryModel_.changeDirectory(mountPath);
2637 }, function(error) {
2638 tracker.stop();
2639 self.alert.show(strf('ARCHIVE_MOUNT_FAILED',
2640 error.fileName, error.message));
2760 }); 2641 });
2761 } 2642 }
2762 }); 2643 });
2763 } else if (id == 'format-device') { 2644 } else if (id == 'format-device') {
2764 this.confirm.show(str('FORMATTING_WARNING'), function() { 2645 this.confirm.show(str('FORMATTING_WARNING'), function() {
2765 chrome.fileBrowserPrivate.formatDevice(urls[0]); 2646 chrome.fileBrowserPrivate.formatDevice(urls[0]);
2766 }); 2647 });
2767 } else if (id == 'gallery') { 2648 } else if (id == 'gallery') {
2768 this.openGallery_(urls); 2649 this.openGallery_(urls);
2769 } else if (id == 'view-pdf' || id == 'view-in-browser' || 2650 } else if (id == 'view-pdf' || id == 'view-in-browser' ||
2770 id == 'install-crx' || id == 'open-hosted') { 2651 id == 'install-crx' || id == 'open-hosted') {
2771 chrome.fileBrowserPrivate.viewFiles(urls, 'default', function(success) { 2652 chrome.fileBrowserPrivate.viewFiles(urls, 'default', function(success) {
2772 if (!success) 2653 if (!success)
2773 console.error('chrome.fileBrowserPrivate.viewFiles failed', urls); 2654 console.error('chrome.fileBrowserPrivate.viewFiles failed', urls);
2774 }); 2655 });
2775 } 2656 }
2776 }; 2657 };
2777 2658
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 /** 2659 /**
2790 * Show a modal-like file viewer/editor on top of the File Manager UI. 2660 * Show a modal-like file viewer/editor on top of the File Manager UI.
2791 * 2661 *
2792 * @param {HTMLElement} popup Popup element. 2662 * @param {HTMLElement} popup Popup element.
2793 * @param {function} closeCallback Function to call after the popup is closed. 2663 * @param {function} closeCallback Function to call after the popup is closed.
2794 */ 2664 */
2795 FileManager.prototype.openFilePopup_ = function(popup, closeCallback) { 2665 FileManager.prototype.openFilePopup_ = function(popup, closeCallback) {
2796 this.closeFilePopup_(); 2666 this.closeFilePopup_();
2797 this.filePopup_ = popup; 2667 this.filePopup_ = popup;
2798 this.filePopupCloseCallback_ = closeCallback; 2668 this.filePopupCloseCallback_ = closeCallback;
(...skipping 577 matching lines...) Expand 10 before | Expand all | Expand 10 after
3376 return true; 3246 return true;
3377 } 3247 }
3378 if (!this.okButton_.disabled) { 3248 if (!this.okButton_.disabled) {
3379 this.onOk_(); 3249 this.onOk_();
3380 return true; 3250 return true;
3381 } 3251 }
3382 return false; 3252 return false;
3383 }; 3253 };
3384 3254
3385 FileManager.prototype.onDirectoryAction = function(entry) { 3255 FileManager.prototype.onDirectoryAction = function(entry) {
3386 var deviceNumber = this.getDeviceNumber(entry); 3256 var mountCondition = this.volumeManager_.getMountCondition(entry.fullPath);
3387 if (deviceNumber != undefined && 3257 if (mountCondition == 'unknown_filesystem') {
3388 this.mountPoints_[deviceNumber].mountCondition ==
3389 'unknown_filesystem') {
3390 return this.showButter(str('UNKNOWN_FILESYSTEM_WARNING')); 3258 return this.showButter(str('UNKNOWN_FILESYSTEM_WARNING'));
3391 } else if (deviceNumber != undefined && 3259 } else if (mountCondition == 'unsupported_filesystem') {
3392 this.mountPoints_[deviceNumber].mountCondition ==
3393 'unsupported_filesystem') {
3394 return this.showButter(str('UNSUPPORTED_FILESYSTEM_WARNING')); 3260 return this.showButter(str('UNSUPPORTED_FILESYSTEM_WARNING'));
3395 } else { 3261 } else {
3396 return this.directoryModel_.changeDirectory(entry.fullPath); 3262 return this.directoryModel_.changeDirectory(entry.fullPath);
3397 } 3263 }
3398 }; 3264 };
3399 3265
3400 /** 3266 /**
3401 * Show or hide the "Low disk space" warning. 3267 * Show or hide the "Low disk space" warning.
3402 * @param {boolean} show True if the box need to be shown. 3268 * @param {boolean} show True if the box need to be shown.
3403 */ 3269 */
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
3457 3323
3458 // Sometimes we rescan the same directory (when mounting GData lazily first, 3324 // Sometimes we rescan the same directory (when mounting GData lazily first,
3459 // then for real). Do not update the location then. 3325 // then for real). Do not update the location then.
3460 if (event.newDirEntry.fullPath != event.previousDirEntry.fullPath) { 3326 if (event.newDirEntry.fullPath != event.previousDirEntry.fullPath) {
3461 this.updateLocation_(event.initial, event.newDirEntry.fullPath); 3327 this.updateLocation_(event.initial, event.newDirEntry.fullPath);
3462 } 3328 }
3463 3329
3464 this.checkFreeSpace_(this.getCurrentDirectory()); 3330 this.checkFreeSpace_(this.getCurrentDirectory());
3465 3331
3466 this.updateTitle_(); 3332 this.updateTitle_();
3467 3333 this.updateGDataStatus_('directory-change');
3468 if (this.filesystemObserverId_)
3469 this.metadataCache_.removeObserver(this.filesystemObserverId_);
3470 if (this.gdataObserverId_)
3471 this.metadataCache_.removeObserver(this.gdataObserverId_);
3472
3473 this.filesystemObserverId_ = this.metadataCache_.addObserver(
3474 this.directoryModel_.getCurrentDirEntry(),
3475 MetadataCache.CHILDREN,
3476 'filesystem',
3477 this.updateMetadataInUI_.bind(this, 'filesystem'));
3478
3479 if (this.isOnGData()) {
3480 this.gdataObserverId_ = this.metadataCache_.addObserver(
3481 this.directoryModel_.getCurrentDirEntry(),
3482 MetadataCache.CHILDREN,
3483 'gdata',
3484 this.updateMetadataInUI_.bind(this, 'gdata'));
3485 }
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 }; 3334 };
3531 3335
3532 FileManager.prototype.findListItemForEvent_ = function(event) { 3336 FileManager.prototype.findListItemForEvent_ = function(event) {
3533 return this.findListItemForNode_(event.srcElement); 3337 return this.findListItemForNode_(event.srcElement);
3534 }; 3338 };
3535 3339
3536 FileManager.prototype.findListItemForNode_ = function(node) { 3340 FileManager.prototype.findListItemForNode_ = function(node) {
3537 var item = this.currentList_.getListItemAncestor(node); 3341 var item = this.currentList_.getListItemAncestor(node);
3538 // TODO(serya): list should check that. 3342 // TODO(serya): list should check that.
3539 return item && this.currentList_.isItem(item) ? item : null; 3343 return item && this.currentList_.isItem(item) ? item : null;
3540 }; 3344 };
3541 3345
3542 /** 3346 /**
3543 * Unload handler for the page. May be called manually for the file picker 3347 * 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 3348 * dialog, because it closes by calling extension API functions that do not
3545 * return. 3349 * return.
3546 */ 3350 */
3547 FileManager.prototype.onUnload_ = function() { 3351 FileManager.prototype.onUnload_ = function() {
3548 if (this.watchedDirectoryUrl_) { 3352 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 }; 3353 };
3565 3354
3566 FileManager.prototype.initiateRename_ = function() { 3355 FileManager.prototype.initiateRename_ = function() {
3567 var item = this.currentList_.ensureLeadItemExists(); 3356 var item = this.currentList_.ensureLeadItemExists();
3568 if (!item) 3357 if (!item)
3569 return; 3358 return;
3570 var label = item.querySelector('.filename-label'); 3359 var label = item.querySelector('.filename-label');
3571 var input = this.renameInput_; 3360 var input = this.renameInput_;
3572 3361
3573 input.value = label.textContent; 3362 input.value = label.textContent;
(...skipping 905 matching lines...) Expand 10 before | Expand all | Expand 10 after
4479 4268
4480 this.directoryModel_.addEventListener('scan-completed', maybeShowBanner); 4269 this.directoryModel_.addEventListener('scan-completed', maybeShowBanner);
4481 this.directoryModel_.addEventListener('rescan-completed', maybeShowBanner); 4270 this.directoryModel_.addEventListener('rescan-completed', maybeShowBanner);
4482 4271
4483 var style = this.document_.createElement('link'); 4272 var style = this.document_.createElement('link');
4484 style.rel = 'stylesheet'; 4273 style.rel = 'stylesheet';
4485 style.href = 'css/gdrive_welcome.css'; 4274 style.href = 'css/gdrive_welcome.css';
4486 this.document_.head.appendChild(style); 4275 this.document_.head.appendChild(style);
4487 }; 4276 };
4488 })(); 4277 })();
4278
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698