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). |
11 * | 11 * |
12 * @constructor | 12 * @constructor |
13 * @param {HTMLElement} dialogDom The DOM node containing the prototypical | 13 * @param {HTMLElement} dialogDom The DOM node containing the prototypical |
14 * dialog UI. | 14 * dialog UI. |
15 */ | 15 */ |
16 function FileManager(dialogDom) { | 16 function FileManager(dialogDom) { |
17 this.dialogDom_ = dialogDom; | 17 this.dialogDom_ = dialogDom; |
18 this.filesystem_ = null; | 18 this.filesystem_ = null; |
19 this.params_ = location.search ? | 19 this.params_ = location.search ? |
20 JSON.parse(decodeURIComponent(location.search.substr(1))) : | 20 JSON.parse(decodeURIComponent(location.search.substr(1))) : |
21 {}; | 21 {}; |
22 | 22 |
23 this.listType_ = null; | 23 this.listType_ = null; |
| 24 this.showDelayTimeout_ = null; |
24 | 25 |
25 this.selection = null; | 26 this.selection = null; |
26 | 27 |
27 this.butterTimer_ = null; | 28 this.butterTimer_ = null; |
28 this.currentButter_ = null; | 29 this.currentButter_ = null; |
29 this.butterLastShowTime_ = 0; | 30 this.butterLastShowTime_ = 0; |
30 | 31 |
31 this.watchedDirectoryUrl_ = null; | |
32 this.filesystemObserverId_ = null; | 32 this.filesystemObserverId_ = null; |
33 this.gdataObserverId_ = null; | 33 this.gdataObserverId_ = null; |
34 | 34 |
35 this.commands_ = {}; | 35 this.commands_ = {}; |
36 | 36 |
37 this.thumbnailUrlCache_ = {}; | 37 this.thumbnailUrlCache_ = {}; |
38 | 38 |
39 this.document_ = dialogDom.ownerDocument; | 39 this.document_ = dialogDom.ownerDocument; |
40 this.dialogType_ = this.params_.type || FileManager.DialogType.FULL_PAGE; | 40 this.dialogType_ = this.params_.type || FileManager.DialogType.FULL_PAGE; |
41 | 41 |
42 metrics.recordEnum('Create', this.dialogType_, | 42 metrics.recordEnum('Create', this.dialogType_, |
43 [FileManager.DialogType.SELECT_FOLDER, | 43 [FileManager.DialogType.SELECT_FOLDER, |
44 FileManager.DialogType.SELECT_SAVEAS_FILE, | 44 FileManager.DialogType.SELECT_SAVEAS_FILE, |
45 FileManager.DialogType.SELECT_OPEN_FILE, | 45 FileManager.DialogType.SELECT_OPEN_FILE, |
46 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, | 46 FileManager.DialogType.SELECT_OPEN_MULTI_FILE, |
47 FileManager.DialogType.FULL_PAGE]); | 47 FileManager.DialogType.FULL_PAGE]); |
48 | 48 |
49 // TODO(dgozman): This will be changed to LocaleInfo. | 49 // TODO(dgozman): This will be changed to LocaleInfo. |
50 this.locale_ = new v8Locale(navigator.language); | 50 this.locale_ = new v8Locale(navigator.language); |
51 | 51 |
52 this.initFileSystem_(); | 52 this.initFileSystem_(); |
| 53 this.volumeManager_ = VolumeManager.getInstance(); |
53 this.initDom_(); | 54 this.initDom_(); |
54 this.initDialogType_(); | 55 this.initDialogType_(); |
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". |
63 (function() { | 63 (function() { |
64 | 64 |
65 // Private variables and helper functions. | 65 // Private variables and helper functions. |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 15 matching lines...) Expand all Loading... |
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 |
257 /** | 245 /** |
| 246 * FileWatcher that also watches for metadata changes. |
| 247 * @extends {FileWatcher} |
| 248 */ |
| 249 FileManager.MetadataFileWatcher = function(fileManager) { |
| 250 FileWatcher.call(this, |
| 251 fileManager.filesystem_.root, |
| 252 fileManager.directoryModel_, |
| 253 fileManager.volumeManager_); |
| 254 this.metadataCache_ = fileManager.metadataCache_; |
| 255 |
| 256 this.filesystemChanngeHandler_ = |
| 257 fileManager.updateMetadataInUI_.bind(fileManager, 'filesystem'); |
| 258 this.gdataChanngeHandler_ = |
| 259 fileManager.updateMetadataInUI_.bind(fileManager, 'gdata'); |
| 260 |
| 261 this.filesystemObserverId_ = null; |
| 262 this.gdataObserverId_ = null; |
| 263 }; |
| 264 |
| 265 FileManager.MetadataFileWatcher.prototype.__proto__ = FileWatcher.prototype; |
| 266 |
| 267 /** |
| 268 * Changed metadata observers for the new directory. |
| 269 * @override |
| 270 * @param {DirectoryEntryi?} entry New watched directory entry. |
| 271 */ |
| 272 FileManager.MetadataFileWatcher.prototype.changeWatchedEntry = |
| 273 function(entry) { |
| 274 FileWatcher.prototype.changeWatchedEntry.call(this, entry); |
| 275 |
| 276 if (this.filesystemObserverId_) |
| 277 this.metadataCache_.removeObserver(this.filesystemObserverId_); |
| 278 if (this.gdataObserverId_) |
| 279 this.metadataCache_.removeObserver(this.gdataObserverId_); |
| 280 this.filesystemObserverId_ = null; |
| 281 this.gdataObserverId_ = null; |
| 282 if (!entry) |
| 283 return; |
| 284 |
| 285 this.filesystemObserverId_ = this.metadataCache_.addObserver( |
| 286 entry, |
| 287 MetadataCache.CHILDREN, |
| 288 'filesystem', |
| 289 this.filesystemChanngeHandler_); |
| 290 |
| 291 if (DirectoryModel.getRootType(entry.fullPath) == |
| 292 DirectoryModel.RootType.GDATA) { |
| 293 this.gdataObserverId_ = this.metadataCache_.addObserver( |
| 294 entry, |
| 295 MetadataCache.CHILDREN, |
| 296 'gdata', |
| 297 this.gdataChanngeHandler_); |
| 298 } |
| 299 }; |
| 300 |
| 301 /** |
258 * Load translated strings. | 302 * Load translated strings. |
259 */ | 303 */ |
260 FileManager.initStrings = function(callback) { | 304 FileManager.initStrings = function(callback) { |
261 chrome.fileBrowserPrivate.getStrings(function(strings) { | 305 chrome.fileBrowserPrivate.getStrings(function(strings) { |
262 localStrings = new LocalStrings(strings); | 306 localStrings = new LocalStrings(strings); |
263 if (callback) | 307 if (callback) |
264 callback(); | 308 callback(); |
265 }); | 309 }); |
266 }; | 310 }; |
267 | 311 |
| 312 /** |
| 313 * FileManager initially created hidden to prevent flickering. |
| 314 * When DOM is almost constructed it need to be shown. Cancels |
| 315 * delayed show. |
| 316 */ |
| 317 FileManager.prototype.show_ = function() { |
| 318 if (this.showDelayTimeout_) { |
| 319 clearTimeout(this.showDelayTimeout_); |
| 320 showDelayTimeout_ = null; |
| 321 } |
| 322 this.dialogDom_.classList.add('loaded'); |
| 323 }; |
| 324 |
| 325 /** |
| 326 * If initialization code think that right after initialization |
| 327 * something going to be shown instead of just a file list (like Gallery) |
| 328 * it may delay show to prevent flickering. However initialization may take |
| 329 * significant time and we don't want to keep it hidden for too long. |
| 330 * So it will be shown not more than in 0.5 sec. If initialization completed |
| 331 * the page must show immediatelly. |
| 332 * |
| 333 * @param {number} delay In milliseconds. |
| 334 */ |
| 335 FileManager.prototype.delayShow_ = function(delay) { |
| 336 if (!this.showDelayTimeout_) { |
| 337 this.showDelayTimeout_ = setTimeout(function() { |
| 338 this.showDelayTimeout_ = null; |
| 339 this.show_(); |
| 340 }.bind(this), delay); |
| 341 } |
| 342 }; |
| 343 |
268 // Instance methods. | 344 // Instance methods. |
269 | 345 |
270 /** | 346 /** |
271 * Request local file system, resolve roots and init_ after that. | 347 * Request local file system, resolve roots and init_ after that. |
272 * @private | 348 * @private |
273 */ | 349 */ |
274 FileManager.prototype.initFileSystem_ = function() { | 350 FileManager.prototype.initFileSystem_ = function() { |
275 util.installFileErrorToString(); | 351 util.installFileErrorToString(); |
276 // Replace the default unit in util to translated unit. | 352 // Replace the default unit in util to translated unit. |
277 util.UNITS = [str('SIZE_KB'), | 353 util.UNITS = [str('SIZE_KB'), |
278 str('SIZE_MB'), | 354 str('SIZE_MB'), |
279 str('SIZE_GB'), | 355 str('SIZE_GB'), |
280 str('SIZE_TB'), | 356 str('SIZE_TB'), |
281 str('SIZE_PB')]; | 357 str('SIZE_PB')]; |
282 | 358 |
283 metrics.startInterval('Load.FileSystem'); | 359 metrics.startInterval('Load.FileSystem'); |
284 | 360 |
285 var self = this; | 361 var self = this; |
286 | 362 var downcount = 2; |
287 // The list of active mount points to distinct them from other directories. | 363 function done() { |
288 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { | 364 if (--downcount == 0) |
289 self.setMountPoints_(mountPoints); | |
290 onDone(); | |
291 }); | |
292 | |
293 function onDone() { | |
294 if (self.mountPoints_ && self.filesystem_) | |
295 self.init_(); | 365 self.init_(); |
296 } | 366 } |
297 | 367 |
298 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { | 368 chrome.fileBrowserPrivate.requestLocalFileSystem(function(filesystem) { |
299 metrics.recordInterval('Load.FileSystem'); | 369 metrics.recordInterval('Load.FileSystem'); |
300 self.filesystem_ = filesystem; | 370 self.filesystem_ = filesystem; |
301 onDone(); | 371 done(); |
| 372 }); |
| 373 |
| 374 // GDATA preferences should be initialized before creating DirectoryModel |
| 375 // to tot rebuild the roots list. |
| 376 this.updateNetworkStateAndGDataPreferences_(function() { |
| 377 done(); |
302 }); | 378 }); |
303 }; | 379 }; |
304 | 380 |
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 /** | 381 /** |
313 * Continue initializing the file manager after resolving roots. | 382 * Continue initializing the file manager after resolving roots. |
314 */ | 383 */ |
315 FileManager.prototype.init_ = function() { | 384 FileManager.prototype.init_ = function() { |
316 metrics.startInterval('Load.DOM'); | 385 metrics.startInterval('Load.DOM'); |
317 this.initCommands_(); | 386 this.initCommands_(); |
318 | 387 |
319 this.metadataCache_ = MetadataCache.createFull(); | 388 this.metadataCache_ = MetadataCache.createFull(); |
320 | 389 |
321 this.shortDateFormatter_ = | 390 this.shortDateFormatter_ = |
(...skipping 11 matching lines...) Expand all Loading... |
333 | 402 |
334 this.table_.startBatchUpdates(); | 403 this.table_.startBatchUpdates(); |
335 this.grid_.startBatchUpdates(); | 404 this.grid_.startBatchUpdates(); |
336 | 405 |
337 this.initFileList_(); | 406 this.initFileList_(); |
338 this.initDialogs_(); | 407 this.initDialogs_(); |
339 | 408 |
340 window.addEventListener('popstate', this.onPopState_.bind(this)); | 409 window.addEventListener('popstate', this.onPopState_.bind(this)); |
341 window.addEventListener('unload', this.onUnload_.bind(this)); | 410 window.addEventListener('unload', this.onUnload_.bind(this)); |
342 | 411 |
343 this.directoryModel_.addEventListener('directory-changed', | 412 var dm = this.directoryModel_; |
344 this.onDirectoryChanged_.bind(this)); | 413 dm.addEventListener('directory-changed', |
| 414 this.onDirectoryChanged_.bind(this)); |
345 var self = this; | 415 var self = this; |
346 this.directoryModel_.addEventListener('begin-update-files', function() { | 416 dm.addEventListener('begin-update-files', function() { |
347 self.currentList_.startBatchUpdates(); | 417 self.currentList_.startBatchUpdates(); |
348 }); | 418 }); |
349 this.directoryModel_.addEventListener('end-update-files', function() { | 419 dm.addEventListener('end-update-files', function() { |
350 self.restoreItemBeingRenamed_(); | 420 self.restoreItemBeingRenamed_(); |
351 self.currentList_.endBatchUpdates(); | 421 self.currentList_.endBatchUpdates(); |
352 }); | 422 }); |
353 this.directoryModel_.addEventListener('scan-started', | 423 dm.addEventListener('scan-started', this.showSpinnerLater_.bind(this)); |
354 this.showSpinnerLater_.bind(this)); | 424 dm.addEventListener('scan-completed', this.showSpinner_.bind(this, false)); |
355 this.directoryModel_.addEventListener('scan-completed', | 425 dm.addEventListener('scan-completed', |
356 this.showSpinner_.bind(this, false)); | 426 this.refreshCurrentDirectoryMetadata_.bind(this)); |
357 this.directoryModel_.addEventListener('scan-completed', | 427 dm.addEventListener('rescan-completed', |
358 this.refreshCurrentDirectoryMetadata_.bind(this)); | 428 this.refreshCurrentDirectoryMetadata_.bind(this)); |
359 this.directoryModel_.addEventListener('rescan-completed', | |
360 this.refreshCurrentDirectoryMetadata_.bind(this)); | |
361 this.addEventListener('selection-summarized', | 429 this.addEventListener('selection-summarized', |
362 this.onSelectionSummarized_.bind(this)); | 430 this.onSelectionSummarized_.bind(this)); |
363 | 431 |
364 // The list of archives requested to mount. We will show contents once | 432 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 | 433 |
371 chrome.fileBrowserPrivate.onFileChanged.addListener( | 434 var stateChangeHandler = |
372 this.onFileChanged_.bind(this)); | 435 this.onNetworkStateOrGDataPreferencesChanged_.bind(this); |
373 | 436 chrome.fileBrowserPrivate.onGDataPreferencesChanged.addListener( |
374 var queryGDataPreferences = function() { | 437 stateChangeHandler); |
375 chrome.fileBrowserPrivate.getGDataPreferences( | 438 chrome.fileBrowserPrivate.onNetworkConnectionChanged.addListener( |
376 this.onGDataPreferencesChanged_.bind(this)); | 439 stateChangeHandler); |
377 }.bind(this); | 440 stateChangeHandler(); |
378 queryGDataPreferences(); | |
379 chrome.fileBrowserPrivate.onGDataPreferencesChanged. | |
380 addListener(queryGDataPreferences); | |
381 | |
382 var queryNetworkConnectionState = function() { | |
383 chrome.fileBrowserPrivate.getNetworkConnectionState( | |
384 this.onNetworkConnectionChanged_.bind(this)); | |
385 }.bind(this); | |
386 queryNetworkConnectionState(); | |
387 chrome.fileBrowserPrivate.onNetworkConnectionChanged. | |
388 addListener(queryNetworkConnectionState); | |
389 | |
390 var invokeHandler = !this.params_.selectOnly; | |
391 if (this.isStartingOnGData_()) { | |
392 // We are opening on a GData path. Mount GData and show | |
393 // "Loading Google Docs" message until the directory content loads. | |
394 this.dialogContainer_.setAttribute('unmounted', true); | |
395 this.initGData_(true /* dirChanged */); | |
396 // This is a one-time handler (will be nulled out on the first call). | |
397 this.setupCurrentDirectoryPostponed_ = function(event) { | |
398 this.directoryModel_.removeEventListener('directory-changed', | |
399 this.setupCurrentDirectoryPostponed_); | |
400 this.setupCurrentDirectoryPostponed_ = null; | |
401 if (event) // If called as an event handler just exit silently. | |
402 return; | |
403 this.setupCurrentDirectory_( | |
404 invokeHandler, false /* blankWhileOpeningAFile */); | |
405 }.bind(this); | |
406 this.directoryModel_.addEventListener('directory-changed', | |
407 this.setupCurrentDirectoryPostponed_); | |
408 } else { | |
409 this.setupCurrentDirectory_( | |
410 invokeHandler, true /* blankWhileOpeningAFile */); | |
411 } | |
412 | |
413 if (this.isGDataEnabled()) | |
414 this.setupGDataWelcome_(); | |
415 | 441 |
416 this.summarizeSelection_(); | 442 this.summarizeSelection_(); |
417 | 443 |
418 var sortField = | 444 var sortField = |
419 window.localStorage['sort-field-' + this.dialogType_] || | 445 window.localStorage['sort-field-' + this.dialogType_] || |
420 'modificationTime'; | 446 'modificationTime'; |
421 var sortDirection = | 447 var sortDirection = |
422 window.localStorage['sort-direction-' + this.dialogType_] || 'desc'; | 448 window.localStorage['sort-direction-' + this.dialogType_] || 'desc'; |
423 this.directoryModel_.sortFileList(sortField, sortDirection); | 449 this.directoryModel_.sortFileList(sortField, sortDirection); |
424 | 450 |
425 this.refocus(); | 451 this.refocus(); |
426 | 452 |
427 this.metadataProvider_ = | 453 this.metadataProvider_ = |
428 new MetadataProvider(this.filesystem_.root.toURL()); | 454 new MetadataProvider(this.filesystem_.root.toURL()); |
429 | 455 |
430 // PyAuto tests monitor this state by polling this variable | 456 // PyAuto tests monitor this state by polling this variable |
431 this.__defineGetter__('workerInitialized_', function() { | 457 this.__defineGetter__('workerInitialized_', function() { |
432 return self.getMetadataProvider().isInitialized(); | 458 return self.getMetadataProvider().isInitialized(); |
433 }); | 459 }); |
434 | 460 |
435 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE) | 461 if (this.dialogType_ == FileManager.DialogType.FULL_PAGE) |
436 this.initDataTransferOperations_(); | 462 this.initDataTransferOperations_(); |
437 | 463 |
438 this.table_.endBatchUpdates(); | 464 this.table_.endBatchUpdates(); |
439 this.grid_.endBatchUpdates(); | 465 this.grid_.endBatchUpdates(); |
440 | 466 |
| 467 // Show the page now unless it's already delayed. |
| 468 this.delayShow_(0); |
| 469 |
441 metrics.recordInterval('Load.DOM'); | 470 metrics.recordInterval('Load.DOM'); |
442 metrics.recordInterval('Load.Total'); | 471 metrics.recordInterval('Load.Total'); |
443 }; | 472 }; |
444 | 473 |
445 FileManager.prototype.initDataTransferOperations_ = function() { | 474 FileManager.prototype.initDataTransferOperations_ = function() { |
446 this.copyManager_ = new FileCopyManager(this.filesystem_.root); | 475 this.copyManager_ = new FileCopyManager(this.filesystem_.root); |
447 this.copyManager_.addEventListener('copy-progress', | 476 this.copyManager_.addEventListener('copy-progress', |
448 this.onCopyProgress_.bind(this)); | 477 this.onCopyProgress_.bind(this)); |
449 this.copyManager_.addEventListener('copy-operation-complete', | 478 this.copyManager_.addEventListener('copy-operation-complete', |
450 this.onCopyManagerOperationComplete_.bind(this)); | 479 this.onCopyManagerOperationComplete_.bind(this)); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); | 548 this.filenameInput_ = this.dialogDom_.querySelector('.filename-input'); |
520 this.taskItems_ = this.dialogDom_.querySelector('#tasks'); | 549 this.taskItems_ = this.dialogDom_.querySelector('#tasks'); |
521 this.okButton_ = this.dialogDom_.querySelector('.ok'); | 550 this.okButton_ = this.dialogDom_.querySelector('.ok'); |
522 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); | 551 this.cancelButton_ = this.dialogDom_.querySelector('.cancel'); |
523 this.deleteButton_ = this.dialogDom_.querySelector('#delete-button'); | 552 this.deleteButton_ = this.dialogDom_.querySelector('#delete-button'); |
524 this.table_ = this.dialogDom_.querySelector('.detail-table'); | 553 this.table_ = this.dialogDom_.querySelector('.detail-table'); |
525 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid'); | 554 this.grid_ = this.dialogDom_.querySelector('.thumbnail-grid'); |
526 this.spinner_ = this.dialogDom_.querySelector('.spinner'); | 555 this.spinner_ = this.dialogDom_.querySelector('.spinner'); |
527 this.showSpinner_(false); | 556 this.showSpinner_(false); |
528 this.butter_ = this.dialogDom_.querySelector('.butter-bar'); | 557 this.butter_ = this.dialogDom_.querySelector('.butter-bar'); |
529 this.unmountedPanel_ = this.dialogDom_.querySelector('.unmounted-panel'); | 558 this.unmountedPanel_ = this.dialogDom_.querySelector('#unmounted-panel'); |
530 | 559 |
531 cr.ui.decorate('#gdata-settings', cr.ui.MenuButton); | 560 cr.ui.decorate('#gdata-settings', cr.ui.MenuButton); |
532 cr.ui.Table.decorate(this.table_); | 561 cr.ui.Table.decorate(this.table_); |
533 cr.ui.Grid.decorate(this.grid_); | 562 cr.ui.Grid.decorate(this.grid_); |
534 | 563 |
535 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); | 564 this.document_.addEventListener('keydown', this.onKeyDown_.bind(this)); |
536 // Disable the default browser context menu. | 565 // Disable the default browser context menu. |
537 this.document_.addEventListener('contextmenu', | 566 this.document_.addEventListener('contextmenu', |
538 function(e) { e.preventDefault() }); | 567 function(e) { e.preventDefault() }); |
539 | 568 |
(...skipping 29 matching lines...) Expand all Loading... |
569 | 598 |
570 this.decorateSplitter( | 599 this.decorateSplitter( |
571 this.dialogDom_.querySelector('div.sidebar-splitter')); | 600 this.dialogDom_.querySelector('div.sidebar-splitter')); |
572 | 601 |
573 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); | 602 this.dialogContainer_ = this.dialogDom_.querySelector('.dialog-container'); |
574 this.dialogDom_.querySelector('#detail-view').addEventListener( | 603 this.dialogDom_.querySelector('#detail-view').addEventListener( |
575 'click', this.onDetailViewButtonClick_.bind(this)); | 604 'click', this.onDetailViewButtonClick_.bind(this)); |
576 this.dialogDom_.querySelector('#thumbnail-view').addEventListener( | 605 this.dialogDom_.querySelector('#thumbnail-view').addEventListener( |
577 'click', this.onThumbnailViewButtonClick_.bind(this)); | 606 'click', this.onThumbnailViewButtonClick_.bind(this)); |
578 | 607 |
579 // When we show the page for the first time we want to avoid | |
580 // the GDrive settings button animation, so we set the attribute ASAP. | |
581 if (this.isStartingOnGData_()) | |
582 this.dialogContainer_.setAttribute('gdata', true); | |
583 | |
584 this.syncButton = this.dialogDom_.querySelector('#gdata-sync-settings'); | 608 this.syncButton = this.dialogDom_.querySelector('#gdata-sync-settings'); |
585 this.syncButton.addEventListener('click', this.onGDataPrefClick_.bind( | 609 this.syncButton.addEventListener('click', this.onGDataPrefClick_.bind( |
586 this, 'cellularDisabled', false /* not inverted */)); | 610 this, 'cellularDisabled', false /* not inverted */)); |
587 | 611 |
588 this.hostedButton = this.dialogDom_.querySelector('#gdata-hosted-settings'); | 612 this.hostedButton = this.dialogDom_.querySelector('#gdata-hosted-settings'); |
589 this.hostedButton.addEventListener('click', this.onGDataPrefClick_.bind( | 613 this.hostedButton.addEventListener('click', this.onGDataPrefClick_.bind( |
590 this, 'hostedFilesDisabled', true /* inverted */)); | 614 this, 'hostedFilesDisabled', true /* inverted */)); |
591 | 615 |
592 cr.ui.ComboButton.decorate(this.taskItems_); | 616 cr.ui.ComboButton.decorate(this.taskItems_); |
593 this.taskItems_.addEventListener('select', | 617 this.taskItems_.addEventListener('select', |
(...skipping 25 matching lines...) Expand all Loading... |
619 this.emptySelectionModel_ = new cr.ui.ListSelectionModel(); | 643 this.emptySelectionModel_ = new cr.ui.ListSelectionModel(); |
620 | 644 |
621 var singleSelection = | 645 var singleSelection = |
622 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || | 646 this.dialogType_ == FileManager.DialogType.SELECT_OPEN_FILE || |
623 this.dialogType_ == FileManager.DialogType.SELECT_FOLDER || | 647 this.dialogType_ == FileManager.DialogType.SELECT_FOLDER || |
624 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE; | 648 this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE; |
625 | 649 |
626 this.directoryModel_ = new DirectoryModel( | 650 this.directoryModel_ = new DirectoryModel( |
627 this.filesystem_.root, | 651 this.filesystem_.root, |
628 singleSelection, | 652 singleSelection, |
629 this.metadataCache_); | 653 this.metadataCache_, |
| 654 this.volumeManager_, |
| 655 this.isGDataEnabled()); |
| 656 |
| 657 this.directoryModel_.start(); |
| 658 |
| 659 this.fileWatcher_ = new FileManager.MetadataFileWatcher(this); |
| 660 this.fileWatcher_.start(); |
630 | 661 |
631 var dataModel = this.directoryModel_.getFileList(); | 662 var dataModel = this.directoryModel_.getFileList(); |
632 var collator = this.collator_; | 663 var collator = this.collator_; |
633 // TODO(dgozman): refactor comparison functions together with | 664 // TODO(dgozman): refactor comparison functions together with |
634 // render/update/display. | 665 // render/update/display. |
635 dataModel.setCompareFunction('name', function(a, b) { | 666 dataModel.setCompareFunction('name', function(a, b) { |
636 return collator.compare(a.name, b.name); | 667 return collator.compare(a.name, b.name); |
637 }); | 668 }); |
638 dataModel.setCompareFunction('modificationTime', | 669 dataModel.setCompareFunction('modificationTime', |
639 this.compareMtime_.bind(this)); | 670 this.compareMtime_.bind(this)); |
(...skipping 14 matching lines...) Expand all Loading... |
654 this.initGrid_(); | 685 this.initGrid_(); |
655 this.initRootsList_(); | 686 this.initRootsList_(); |
656 | 687 |
657 var listType = FileManager.ListType.DETAIL; | 688 var listType = FileManager.ListType.DETAIL; |
658 if (FileManager.DialogType.isModal(this.dialogType_)) | 689 if (FileManager.DialogType.isModal(this.dialogType_)) |
659 listType = window.localStorage['listType-' + this.dialogType_] || | 690 listType = window.localStorage['listType-' + this.dialogType_] || |
660 FileManager.ListType.DETAIL; | 691 FileManager.ListType.DETAIL; |
661 this.setListType(listType); | 692 this.setListType(listType); |
662 | 693 |
663 this.textSearchState_ = {text: '', date: new Date()}; | 694 this.textSearchState_ = {text: '', date: new Date()}; |
| 695 |
| 696 this.volumeManager_.addEventListener('gdata-status-changed', |
| 697 this.updateGDataUnmountedPanel_.bind(this)); |
| 698 if (this.params_.mountTriggered) { |
| 699 this.volumeManager_.addEventListener('unexpectedly-unmounted', |
| 700 this.onUnexpectedlyUnmounted_.bind(this)); |
| 701 } |
664 }; | 702 }; |
665 | 703 |
666 FileManager.prototype.initRootsList_ = function() { | 704 FileManager.prototype.initRootsList_ = function() { |
667 this.rootsList_ = this.dialogDom_.querySelector('#roots-list'); | 705 this.rootsList_ = this.dialogDom_.querySelector('#roots-list'); |
668 cr.ui.List.decorate(this.rootsList_); | 706 cr.ui.List.decorate(this.rootsList_); |
669 this.rootsList_.startBatchUpdates(); | |
670 | 707 |
671 var self = this; | 708 var self = this; |
672 this.rootsList_.itemConstructor = function(entry) { | 709 this.rootsList_.itemConstructor = function(entry) { |
673 return self.renderRoot_(entry); | 710 return self.renderRoot_(entry); |
674 }; | 711 }; |
675 | 712 |
676 this.rootsList_.selectionModel = | 713 this.rootsList_.selectionModel = |
677 this.directoryModel_.getRootsListSelectionModel(); | 714 this.directoryModel_.getRootsListSelectionModel(); |
678 | 715 |
679 // TODO(dgozman): add "Add a drive" item. | 716 // TODO(dgozman): add "Add a drive" item. |
680 this.rootsList_.dataModel = this.directoryModel_.getRootsList(); | 717 this.rootsList_.dataModel = this.directoryModel_.getRootsList(); |
681 this.directoryModel_.updateRoots(function() { | |
682 self.rootsList_.endBatchUpdates(); | |
683 }, this.getGDataAccessMode_()); | |
684 }; | 718 }; |
685 | 719 |
686 /** | 720 /** |
687 * @param {boolean} dirChanged True if we just changed to GData directory, | 721 * Shows the panel when current directory is GDATA and it's unmounted. |
688 * False if "Retry" button clicked. | 722 * Hides it otherwise. The pannel shows spinner if GDATA is mounting or |
| 723 * an error message if it failed. |
689 */ | 724 */ |
690 FileManager.prototype.initGData_ = function(dirChanged) { | 725 FileManager.prototype.updateGDataUnmountedPanel_ = function() { |
691 this.initGDataUnmountedPanel_(); | 726 var node = this.dialogContainer_; |
692 | 727 if (this.isOnGData()) { |
693 this.unmountedPanel_.removeAttribute('error'); | 728 var status = this.volumeManager_.getGDataStatus(); |
694 if (dirChanged) { | 729 if (status == VolumeManager.GDataStatus.MOUNTING || |
695 // When changing to GData directory we want to see a clear panel. | 730 status == VolumeManager.GDataStatus.ERROR) { |
696 this.unmountedPanel_.removeAttribute('retry'); | 731 this.ensureGDataUnmountedPanelInitialized_(); |
697 if (this.gdataLoadingTimer_) { // Show immediately if already loading. | |
698 this.unmountedPanel_.setAttribute('loading', true); | |
699 } else { | |
700 this.unmountedPanel_.removeAttribute('loading'); | |
701 setTimeout(function() { | |
702 if (this.gdataLoadingTimer_) { // Still loading. | |
703 this.unmountedPanel_.setAttribute('loading', true); | |
704 } | |
705 }.bind(this), 500); | |
706 } | 732 } |
| 733 if (status == VolumeManager.GDataStatus.ERROR) |
| 734 this.unmountedPanel_.classList.add('retry-enabled'); |
| 735 node.setAttribute('gdata', status); |
707 } else { | 736 } else { |
708 // When retrying we do not hide "Retry" and "Learn more". | 737 node.removeAttribute('gdata'); |
709 this.unmountedPanel_.setAttribute('loading', true); | |
710 } | |
711 | |
712 // If the user changed to another directory and then back to GData we | |
713 // re-enter this method while the timer is still active. In this case | |
714 // we only update the UI but do not request the mount again. | |
715 if (this.gdataLoadingTimer_) | |
716 return; | |
717 | |
718 metrics.startInterval('Load.GData'); | |
719 chrome.fileBrowserPrivate.addMount('', 'gdata', {}, | |
720 function(sourcePath) {}); | |
721 | |
722 // This timer could fire before the mount succeeds. We will silently | |
723 // replace the error message with the correct directory contents. | |
724 this.gdataLoadingTimer_ = setTimeout(function() { | |
725 this.gdataLoadingTimer_ = null; | |
726 this.onGDataUnreachable_('GData load timeout'); | |
727 }.bind(this), | |
728 15 * 60 * 1000); | |
729 }; | |
730 | |
731 FileManager.prototype.clearGDataLoadingTimer_ = function(message) { | |
732 if (this.gdataLoadingTimer_) { | |
733 clearTimeout(this.gdataLoadingTimer_); | |
734 this.gdataLoadingTimer_ = null; | |
735 } | 738 } |
736 }; | 739 }; |
737 | 740 |
738 FileManager.prototype.onGDataUnreachable_ = function(message) { | 741 /** |
739 console.warn(message); | 742 * Creates contents for the GDATA unmounted panel. |
740 this.gdataMounted_ = false; | 743 */ |
741 this.gdataMountInfo_ = null; | 744 FileManager.prototype.ensureGDataUnmountedPanelInitialized_ = function() { |
742 this.clearGDataLoadingTimer_(); | 745 var panel = this.unmountedPanel_; |
743 if (this.isOnGData()) { | 746 if (panel.firstElementChild) |
744 this.unmountedPanel_.removeAttribute('loading'); | |
745 this.unmountedPanel_.setAttribute('error', true); | |
746 this.unmountedPanel_.setAttribute('retry', true); | |
747 } | |
748 }; | |
749 | |
750 FileManager.prototype.initGDataUnmountedPanel_ = function() { | |
751 if (this.unmountedPanel_.firstElementChild) | |
752 return; | 747 return; |
753 | 748 |
754 var loading = this.document_.createElement('div'); | 749 function create(parent, tag, className, opt_textContent) { |
755 loading.className = 'gdata loading'; | 750 var div = panel.ownerDocument.createElement(tag); |
756 loading.textContent = str('GDATA_LOADING'); | 751 div.className = className; |
757 this.unmountedPanel_.appendChild(loading); | 752 div.textContent = opt_textContent || ''; |
| 753 parent.appendChild(div); |
| 754 return div; |
| 755 } |
758 | 756 |
759 var spinnerBox = this.document_.createElement('div'); | 757 var loading = create(panel, 'div', 'loading', str('GDATA_LOADING')); |
760 spinnerBox.className = 'spinner-box'; | 758 var spinnerBox = create(loading, 'div', 'spinner-box'); |
761 loading.appendChild(spinnerBox); | 759 create(spinnerBox, 'div', 'spinner'); |
762 | 760 var progress = create(panel, 'div', 'progress'); |
763 var spinner = this.document_.createElement('div'); | |
764 spinner.className = 'spinner'; | |
765 spinnerBox.appendChild(spinner); | |
766 | |
767 var progress = this.document_.createElement('div'); | |
768 progress.className = 'gdata progress'; | |
769 this.unmountedPanel_.appendChild(progress); | |
770 | |
771 chrome.fileBrowserPrivate.onDocumentFeedFetched.addListener( | 761 chrome.fileBrowserPrivate.onDocumentFeedFetched.addListener( |
772 function(fileCount) { | 762 function(fileCount) { |
773 progress.textContent = strf('GDATA_LOADING_PROGRESS', fileCount); | 763 progress.textContent = strf('GDATA_LOADING_PROGRESS', fileCount); |
774 }); | 764 }); |
775 | 765 |
776 var error = this.document_.createElement('div'); | 766 create(panel, 'div', 'error', |
777 error.className = 'gdata error'; | 767 strf('GDATA_CANNOT_REACH', str('GDATA_PRODUCT_NAME'))); |
778 error.textContent = strf('GDATA_CANNOT_REACH', str('GDATA_PRODUCT_NAME')); | |
779 this.unmountedPanel_.appendChild(error); | |
780 | 768 |
781 var retry = this.document_.createElement('button'); | 769 var retryButton = create(panel, 'button', 'retry', str('GDATA_RETRY')); |
782 retry.className = 'gdata retry'; | 770 retryButton.hidden = true; |
783 retry.textContent = str('GDATA_RETRY'); | 771 var vm = this.volumeManager_; |
784 retry.onclick = this.initGData_.bind(this, false /* retry */); | 772 retryButton.onclick = function() { |
785 this.unmountedPanel_.appendChild(retry); | 773 vm.mountGData(function() {}, function() {}); |
| 774 }; |
786 | 775 |
787 var learnMore = this.document_.createElement('div'); | 776 var learnMore = create(panel, 'div', 'learn-more plain-link', |
788 learnMore.className = 'gdata learn-more plain-link'; | 777 str('GDATA_LEARN_MORE')); |
789 learnMore.textContent = str('GDATA_LEARN_MORE'); | 778 learnMore.onclick = this.onExternalLinkClick_.bind(this, |
790 learnMore.addEventListener('click', | 779 GOOGLE_DRIVE_ERROR_HELP_URL); |
791 this.onExternalLinkClick_.bind(this, GOOGLE_DRIVE_ERROR_HELP_URL)); | |
792 this.unmountedPanel_.appendChild(learnMore); | |
793 }; | 780 }; |
794 | 781 |
795 FileManager.prototype.onDataModelSplice_ = function(event) { | 782 FileManager.prototype.onDataModelSplice_ = function(event) { |
796 var checkbox = this.document_.querySelector('#select-all-checkbox'); | 783 var checkbox = this.document_.querySelector('#select-all-checkbox'); |
797 if (checkbox) | 784 if (checkbox) |
798 this.updateSelectAllCheckboxState_(checkbox); | 785 this.updateSelectAllCheckboxState_(checkbox); |
799 }; | 786 }; |
800 | 787 |
801 FileManager.prototype.onDataModelPermuted_ = function(event) { | 788 FileManager.prototype.onDataModelPermuted_ = function(event) { |
802 var sortStatus = this.directoryModel_.getFileList().sortStatus; | 789 var sortStatus = this.directoryModel_.getFileList().sortStatus; |
(...skipping 478 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1281 } | 1268 } |
1282 } | 1269 } |
1283 }; | 1270 }; |
1284 | 1271 |
1285 /** | 1272 /** |
1286 * Handler of file manager operations. Update directory model | 1273 * Handler of file manager operations. Update directory model |
1287 * to reflect operation result iimediatelly (not waiting directory | 1274 * to reflect operation result iimediatelly (not waiting directory |
1288 * update event). | 1275 * update event). |
1289 */ | 1276 */ |
1290 FileManager.prototype.onCopyManagerOperationComplete_ = function(event) { | 1277 FileManager.prototype.onCopyManagerOperationComplete_ = function(event) { |
1291 var currentPath = | 1278 var currentPath = this.directoryModel_.getCurrentDirPath(); |
1292 this.directoryModel_.getCurrentDirPath(); | |
1293 if (this.isOnGData() && this.directoryModel_.isSearching()) | 1279 if (this.isOnGData() && this.directoryModel_.isSearching()) |
1294 return; | 1280 return; |
1295 | 1281 |
1296 function inCurrentDirectory(entry) { | 1282 function inCurrentDirectory(entry) { |
1297 var fullPath = entry.fullPath; | 1283 var fullPath = entry.fullPath; |
1298 var dirPath = fullPath.substr(0, fullPath.length - | 1284 var dirPath = fullPath.substr(0, fullPath.length - |
1299 entry.name.length - 1); | 1285 entry.name.length - 1); |
1300 return dirPath == currentPath; | 1286 return dirPath == currentPath; |
1301 } | 1287 } |
1302 for (var i = 0; i < event.affectedEntries.length; i++) { | 1288 for (var i = 0; i < event.affectedEntries.length; i++) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1338 | 1324 |
1339 case 'delete': | 1325 case 'delete': |
1340 this.deleteEntries(this.selection.entries); | 1326 this.deleteEntries(this.selection.entries); |
1341 return; | 1327 return; |
1342 | 1328 |
1343 case 'newfolder': | 1329 case 'newfolder': |
1344 this.onNewFolderCommand_(event); | 1330 this.onNewFolderCommand_(event); |
1345 return; | 1331 return; |
1346 | 1332 |
1347 case 'unmount': | 1333 case 'unmount': |
1348 this.unmountVolume_(this.directoryModel_.getCurrentRootDirEntry()); | 1334 this.unmountVolume_( |
| 1335 this.directoryModel_.getCurrentRootDirEntry()); |
1349 return; | 1336 return; |
1350 | 1337 |
1351 case 'format': | 1338 case 'format': |
1352 var entry = this.directoryModel_.getCurrentRootDirEntry(); | 1339 var entry = this.directoryModel_.getCurrentRootDirEntry(); |
1353 this.confirm.show(str('FORMATTING_WARNING'), function() { | 1340 this.confirm.show(str('FORMATTING_WARNING'), function() { |
1354 chrome.fileBrowserPrivate.formatDevice(entry.toURL()); | 1341 chrome.fileBrowserPrivate.formatDevice(entry.toURL()); |
1355 }); | 1342 }); |
1356 | 1343 |
1357 return; | 1344 return; |
1358 } | 1345 } |
1359 }; | 1346 }; |
1360 | 1347 |
1361 /** | 1348 /** |
1362 * Respond to the back and forward buttons. | 1349 * Respond to the back and forward buttons. |
1363 */ | 1350 */ |
1364 FileManager.prototype.onPopState_ = function(event) { | 1351 FileManager.prototype.onPopState_ = function(event) { |
1365 this.closeFilePopup_(); | 1352 this.closeFilePopup_(); |
1366 // Nothing left to do if the current directory is not changing. This happens | 1353 this.setupCurrentDirectory_(false /* page loading */); |
1367 // if we are exiting the Gallery. | |
1368 if (this.getPathFromUrlOrParams_() == | |
1369 this.directoryModel_.getCurrentDirEntry().fullPath) | |
1370 return; | |
1371 this.setupCurrentDirectory_(true /* invokeHandler */); | |
1372 }; | 1354 }; |
1373 | 1355 |
1374 FileManager.prototype.requestResize_ = function(timeout) { | 1356 FileManager.prototype.requestResize_ = function(timeout) { |
1375 setTimeout(this.onResize_.bind(this), timeout || 0); | 1357 setTimeout(this.onResize_.bind(this), timeout || 0); |
1376 }; | 1358 }; |
1377 | 1359 |
1378 /** | 1360 /** |
1379 * Resize details and thumb views to fit the new window size. | 1361 * Resize details and thumb views to fit the new window size. |
1380 */ | 1362 */ |
1381 FileManager.prototype.onResize_ = function() { | 1363 FileManager.prototype.onResize_ = function() { |
(...skipping 19 matching lines...) Expand all Loading... |
1401 this.rootsList_.redraw(); | 1383 this.rootsList_.redraw(); |
1402 this.truncateBreadcrumbs_(); | 1384 this.truncateBreadcrumbs_(); |
1403 }; | 1385 }; |
1404 | 1386 |
1405 FileManager.prototype.resolvePath = function( | 1387 FileManager.prototype.resolvePath = function( |
1406 path, resultCallback, errorCallback) { | 1388 path, resultCallback, errorCallback) { |
1407 return util.resolvePath(this.filesystem_.root, path, resultCallback, | 1389 return util.resolvePath(this.filesystem_.root, path, resultCallback, |
1408 errorCallback); | 1390 errorCallback); |
1409 }; | 1391 }; |
1410 | 1392 |
1411 FileManager.prototype.getPathFromUrlOrParams_ = function() { | |
1412 return location.hash ? // Location hash has the highest priority. | |
1413 decodeURI(location.hash.substr(1)) : | |
1414 this.params_.defaultPath; | |
1415 }; | |
1416 | |
1417 /** | 1393 /** |
1418 * Restores current directory and may be a selected item after page load (or | 1394 * Restores current directory and may be a selected item after page load (or |
1419 * reload) or popping a state (after click on back/forward). If location.hash | 1395 * reload) or popping a state (after click on back/forward). If location.hash |
1420 * is present it means that the user has navigated somewhere and that place | 1396 * is present it means that the user has navigated somewhere and that place |
1421 * will be restored. defaultPath primarily is used with save/open dialogs. | 1397 * will be restored. defaultPath primarily is used with save/open dialogs. |
1422 * Default path may also contain a file name. Freshly opened file manager | 1398 * Default path may also contain a file name. Freshly opened file manager |
1423 * window has neither. | 1399 * window has neither. |
1424 * | 1400 * |
1425 * @param {boolean} invokeHandler Whether to invoke the default handler on | 1401 * @param {boolean} pageLoading True if the page is loading, |
1426 * the selected file. | 1402 false if popping state. |
1427 * @param {boolean} opt_blankWhileOpeningAFile Whether to show fade over | |
1428 * the file manager. | |
1429 */ | 1403 */ |
1430 FileManager.prototype.setupCurrentDirectory_ = | 1404 FileManager.prototype.setupCurrentDirectory_ = function(pageLoading) { |
1431 function(invokeHandler, opt_blankWhileOpeningAFile) { | 1405 var path = location.hash ? // Location hash has the highest priority. |
1432 var path = this.getPathFromUrlOrParams_(); | 1406 decodeURI(location.hash.substr(1)) : |
| 1407 this.params_.defaultPath; |
| 1408 |
| 1409 if (!pageLoading && path == this.directoryModel_.getCurrentDirPath()) |
| 1410 return; |
1433 | 1411 |
1434 if (!path) { | 1412 if (!path) { |
1435 this.directoryModel_.setupDefaultPath(); | 1413 this.directoryModel_.setupDefaultPath(); |
1436 return; | 1414 return; |
1437 } | 1415 } |
1438 | 1416 |
1439 // In the FULL_PAGE mode if the hash path points to a file we might have | 1417 // In the FULL_PAGE mode if the hash path points to a file we might have |
1440 // to invoke a task after selecting it. | 1418 // to invoke a task after selecting it. |
1441 // If the file path is in params_ we only want to select the file. | 1419 // If the file path is in params_ we only want to select the file. |
1442 if (invokeHandler && location.hash && | 1420 var invokeHandlers = pageLoading && !this.params_.selectOnly && |
1443 this.dialogType_ == FileManager.DialogType.FULL_PAGE) { | 1421 this.dialogType_ == FileManager.DialogType.FULL_PAGE && |
1444 // To prevent the file list flickering for a moment before the action | 1422 !!location.hash; |
1445 // is executed we hide it under a white div. | 1423 |
1446 var shade; | 1424 if (DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA) { |
1447 if (opt_blankWhileOpeningAFile) { | 1425 var tracker = this.directoryModel_.createDirectoryChangeTracker(); |
1448 shade = this.document_.createElement('div'); | 1426 // Expected finish of setupPath to GData. |
1449 shade.className = 'overlay-pane'; | 1427 tracker.exceptInitialChange = true; |
1450 shade.style.backgroundColor = 'white'; | 1428 tracker.start(); |
1451 this.document_.body.appendChild(shade); | 1429 if (!this.isGDataEnabled()) { |
| 1430 if (pageLoading) |
| 1431 this.show_(); |
| 1432 this.directoryModel_.setupDefaultPath(); |
| 1433 return; |
1452 } | 1434 } |
1453 function removeShade() { | 1435 var gdataPath = '/' + DirectoryModel.GDATA_DIRECTORY; |
1454 if (shade) | 1436 if (this.volumeManager_.isMounted(gdataPath)) { |
1455 shade.parentNode.removeChild(shade); | 1437 this.finishSetupCurrentDirectory_(path, invokeHandlers); |
| 1438 return; |
| 1439 } |
| 1440 if (pageLoading) |
| 1441 this.delayShow_(500); |
| 1442 // Reflect immediatelly in the UI we are on GData and display |
| 1443 // mounting UI. |
| 1444 this.directoryModel_.setupPath(gdataPath); |
| 1445 |
| 1446 if (!this.isOnGData()) { |
| 1447 // Since GDATA is not mounted it should be resolved synchronously |
| 1448 // (no need in asynchronous calls to filesystem API). It is important |
| 1449 // to prevent race condition. |
| 1450 console.error('Expected path set up synchronously'); |
1456 } | 1451 } |
1457 | 1452 |
| 1453 var self = this; |
| 1454 this.volumeManager_.mountGData(function() { |
| 1455 tracker.stop(); |
| 1456 if (!tracker.hasChanged) { |
| 1457 self.finishSetupCurrentDirectory_(path, invokeHandlers); |
| 1458 } |
| 1459 }, function(error) { |
| 1460 tracker.stop(); |
| 1461 }); |
| 1462 } else { |
| 1463 if (invokeHandlers && pageLoading) |
| 1464 this.delayShow_(500); |
| 1465 this.finishSetupCurrentDirectory_(path, invokeHandlers); |
| 1466 } |
| 1467 }; |
| 1468 |
| 1469 /** |
| 1470 * @param {string} path Path to setup. |
| 1471 * @param {boolean} invokeHandlers If thrue and |path| points to a file |
| 1472 * then default handler is triggered. |
| 1473 */ |
| 1474 FileManager.prototype.finishSetupCurrentDirectory_ = function( |
| 1475 path, invokeHandlers) { |
| 1476 if (invokeHandlers) { |
1458 // Keep track of whether the path is identified as an existing leaf | 1477 // Keep track of whether the path is identified as an existing leaf |
1459 // node. Note that onResolve is guaranteed to be called (exactly once) | 1478 // node. Note that onResolve is guaranteed to be called (exactly once) |
1460 // before onLoadedActivateLeaf. | 1479 // before onLoadedActivateLeaf. |
1461 var foundLeaf = true; | 1480 var foundLeaf = true; |
1462 function onResolve(baseName, leafName, exists) { | 1481 function onResolve(baseName, leafName, exists) { |
1463 if (!exists || leafName == '') { | 1482 if (!exists || leafName == '') { |
1464 // Non-existent file or a directory. Remove the shade immediately. | 1483 // Non-existent file or a directory. Remove the shade immediately. |
1465 removeShade(); | |
1466 foundLeaf = false; | 1484 foundLeaf = false; |
| 1485 self.show_(); |
1467 } | 1486 } |
1468 } | 1487 } |
1469 | 1488 |
1470 // TODO(kaznacheev): refactor dispatchDefaultTask to accept an array | 1489 // TODO(kaznacheev): refactor dispatchDefaultTask to accept an array |
1471 // of urls instead of a selection. This will remove the need to wait | 1490 // of urls instead of a selection. This will remove the need to wait |
1472 // until the selection is done. | 1491 // until the selection is done. |
1473 var self = this; | 1492 var self = this; |
1474 function onLoadedActivateLeaf() { | 1493 function onLoadedActivateLeaf() { |
1475 if (foundLeaf) { | 1494 if (foundLeaf) { |
1476 // There are 3 ways we can get here: | 1495 // There are 3 ways we can get here: |
1477 // 1. Invoked from file_manager_util::ViewFile. This can only | 1496 // 1. Invoked from file_manager_util::ViewFile. This can only |
1478 // happen for 'gallery' and 'mount-archive' actions. | 1497 // happen for 'gallery' and 'mount-archive' actions. |
1479 // 2. Reloading a Gallery page. Must be an image or a video file. | 1498 // 2. Reloading a Gallery page. Must be an image or a video file. |
1480 // 3. A user manually entered a URL pointing to a file. | 1499 // 3. A user manually entered a URL pointing to a file. |
1481 if (FileType.isImageOrVideo(path)) { | 1500 if (FileType.isImageOrVideo(path)) { |
1482 self.dispatchInternalTask_('gallery', self.selection.urls); | 1501 self.dispatchInternalTask_('gallery', self.selection.urls); |
1483 } else if (FileType.getMediaType(path) == 'archive') { | 1502 } else if (FileType.getMediaType(path) == 'archive') { |
| 1503 self.show_(); |
1484 self.dispatchInternalTask_('mount-archive', self.selection.urls); | 1504 self.dispatchInternalTask_('mount-archive', self.selection.urls); |
1485 } else { | 1505 } else { |
1486 // Manually entered path, do nothing, remove the shade ASAP. | 1506 self.show_(); |
1487 removeShade(); | |
1488 return; | 1507 return; |
1489 } | 1508 } |
1490 setTimeout(removeShade, 1000); | |
1491 } | 1509 } |
1492 } | 1510 } |
1493 this.directoryModel_.setupPath(path, onLoadedActivateLeaf, onResolve); | 1511 this.directoryModel_.setupPath(path, onLoadedActivateLeaf, onResolve); |
1494 return; | 1512 return; |
1495 } | 1513 } |
1496 | 1514 |
1497 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { | 1515 if (this.dialogType_ == FileManager.DialogType.SELECT_SAVEAS_FILE) { |
1498 this.directoryModel_.setupPath(path, undefined, | 1516 this.directoryModel_.setupPath(path, undefined, |
1499 function(basePath, leafName) { | 1517 function(basePath, leafName) { |
1500 this.filenameInput_.value = leafName; | 1518 this.filenameInput_.value = leafName; |
1501 this.selectDefaultPathInFilenameInput_(); | 1519 this.selectDefaultPathInFilenameInput_(); |
1502 }.bind(this)); | 1520 }.bind(this)); |
1503 return; | 1521 return; |
1504 } | 1522 } |
1505 | 1523 |
| 1524 this.show_(); |
1506 this.directoryModel_.setupPath(path); | 1525 this.directoryModel_.setupPath(path); |
1507 }; | 1526 }; |
1508 | 1527 |
1509 /** | 1528 /** |
1510 * Tweak the UI to become a particular kind of dialog, as determined by the | 1529 * Tweak the UI to become a particular kind of dialog, as determined by the |
1511 * dialog type parameter passed to the constructor. | 1530 * dialog type parameter passed to the constructor. |
1512 */ | 1531 */ |
1513 FileManager.prototype.initDialogType_ = function() { | 1532 FileManager.prototype.initDialogType_ = function() { |
1514 var defaultTitle; | 1533 var defaultTitle; |
1515 var okLabel = str('OPEN_LABEL'); | 1534 var okLabel = str('OPEN_LABEL'); |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1775 } | 1794 } |
1776 }; | 1795 }; |
1777 li.addEventListener('mousedown', handleClick); | 1796 li.addEventListener('mousedown', handleClick); |
1778 li.addEventListener(cr.ui.TouchHandler.EventType.TOUCH_START, handleClick); | 1797 li.addEventListener(cr.ui.TouchHandler.EventType.TOUCH_START, handleClick); |
1779 | 1798 |
1780 var rootType = DirectoryModel.getRootType(entry.fullPath); | 1799 var rootType = DirectoryModel.getRootType(entry.fullPath); |
1781 | 1800 |
1782 var div = this.document_.createElement('div'); | 1801 var div = this.document_.createElement('div'); |
1783 div.className = 'root-label'; | 1802 div.className = 'root-label'; |
1784 | 1803 |
1785 var icon = rootType; | |
1786 var deviceNumber = this.getDeviceNumber(entry); | |
1787 | |
1788 if (deviceNumber != undefined) { | |
1789 var mountCondition = this.mountPoints_[deviceNumber].mountCondition; | |
1790 if (mountCondition == 'unknown_filesystem' || | |
1791 mountCondition == 'unsupported_filesystem') | |
1792 icon = 'unreadable'; | |
1793 } | |
1794 | |
1795 div.setAttribute('icon', icon); | |
1796 | |
1797 div.textContent = this.getRootLabel_(entry.fullPath); | 1804 div.textContent = this.getRootLabel_(entry.fullPath); |
1798 li.appendChild(div); | 1805 li.appendChild(div); |
1799 | 1806 |
1800 if (rootType == DirectoryModel.RootType.ARCHIVE || | 1807 if (rootType == DirectoryModel.RootType.ARCHIVE || |
1801 rootType == DirectoryModel.RootType.REMOVABLE) { | 1808 rootType == DirectoryModel.RootType.REMOVABLE) { |
1802 if (entry.unmounting) { | 1809 var eject = this.document_.createElement('div'); |
1803 li.setAttribute('disabled', 'disabled'); | 1810 eject.className = 'root-eject'; |
1804 } else { | 1811 eject.addEventListener('click', function(event) { |
1805 var eject = this.document_.createElement('div'); | 1812 event.stopPropagation(); |
1806 eject.className = 'root-eject'; | 1813 this.unmountVolume_(entry); |
1807 eject.addEventListener('click', function(event) { | 1814 }.bind(this)); |
1808 event.stopPropagation(); | 1815 // Block other mouse handlers. |
1809 this.unmountVolume_(entry); | 1816 eject.addEventListener('mouseup', function(e) { e.stopPropagation() }); |
1810 }.bind(this)); | 1817 eject.addEventListener('mousedown', function(e) { e.stopPropagation() }); |
1811 // Block other mouse handlers. | 1818 li.appendChild(eject); |
1812 eject.addEventListener('mouseup', function(e) { e.stopPropagation() }); | |
1813 eject.addEventListener('mousedown', function(e) { e.stopPropagation() })
; | |
1814 li.appendChild(eject); | |
1815 | 1819 |
1816 cr.ui.contextMenuHandler.setContextMenu(li, this.rootsContextMenu_); | 1820 cr.ui.contextMenuHandler.setContextMenu(li, this.rootsContextMenu_); |
1817 } | |
1818 } | 1821 } |
1819 | 1822 |
1820 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); | 1823 cr.defineProperty(li, 'lead', cr.PropertyKind.BOOL_ATTR); |
1821 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); | 1824 cr.defineProperty(li, 'selected', cr.PropertyKind.BOOL_ATTR); |
| 1825 |
| 1826 var icon = rootType; |
| 1827 if (this.volumeManager_.isUnreadable(entry.fullPath)) { |
| 1828 icon = 'unreadable'; |
| 1829 } |
| 1830 div.setAttribute('icon', icon); |
| 1831 |
1822 return li; | 1832 return li; |
1823 }; | 1833 }; |
1824 | 1834 |
1825 /** | 1835 /** |
1826 * Unmounts device. | 1836 * Unmounts device. |
1827 * @param {Entry} entry The entry to unmount. | 1837 * @param {Entry} entry The entry to unmount. |
1828 */ | 1838 */ |
1829 FileManager.prototype.unmountVolume_ = function(entry) { | 1839 FileManager.prototype.unmountVolume_ = function(entry) { |
1830 this.directoryModel_.prepareUnmount(entry.fullPath); | 1840 listItem = this.rootsList_.getListItem(entry); |
1831 this.unmountRequests_.push(entry.fullPath); | 1841 if (listItem) |
1832 chrome.fileBrowserPrivate.removeMount(entry.toURL()); | 1842 listItem.setAttribute('disabled', ''); |
| 1843 var self = this; |
| 1844 this.volumeManager_.unmount(entry.fullPath, function() {}, |
| 1845 function(error) { |
| 1846 if (listItem) |
| 1847 listItem.removeAttribute('disabled'); |
| 1848 self.alert.show(strf('UNMOUNT_FAILED', error.message)); |
| 1849 }); |
1833 }; | 1850 }; |
1834 | 1851 |
1835 FileManager.prototype.updateGDataStyle_ = function( | 1852 FileManager.prototype.updateGDataStyle_ = function( |
1836 listItem, entry, gdata) { | 1853 listItem, entry, gdata) { |
1837 if (!this.isOnGData() || !gdata) | 1854 if (!this.isOnGData() || !gdata) |
1838 return; | 1855 return; |
1839 | 1856 |
1840 if (!entry.isDirectory) { | 1857 if (!entry.isDirectory) { |
1841 if (!gdata.availableOffline) | 1858 if (!gdata.availableOffline) |
1842 listItem.classList.add('dim-offline'); | 1859 listItem.classList.add('dim-offline'); |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2193 | 2210 |
2194 if (entry.isFile) { | 2211 if (entry.isFile) { |
2195 selection.bytes += filesystem.size; | 2212 selection.bytes += filesystem.size; |
2196 } | 2213 } |
2197 } | 2214 } |
2198 | 2215 |
2199 this.dispatchEvent(new cr.Event('selection-summarized')); | 2216 this.dispatchEvent(new cr.Event('selection-summarized')); |
2200 }.bind(this)); | 2217 }.bind(this)); |
2201 | 2218 |
2202 if (this.isOnGData()) { | 2219 if (this.isOnGData()) { |
| 2220 function predicate(p) { |
| 2221 return !(p && p.availableOffline); |
| 2222 } |
2203 this.metadataCache_.get(selection.urls, 'gdata', function(props) { | 2223 this.metadataCache_.get(selection.urls, 'gdata', function(props) { |
2204 selection.allGDataFilesPresent = | 2224 selection.allGDataFilesPresent = |
2205 props.filter(function(p) {return !p.availableOffline}).length == 0; | 2225 props.filter(predicate).length == 0; |
2206 this.updateOkButton_(); | 2226 this.updateOkButton_(); |
2207 }.bind(this)); | 2227 }.bind(this)); |
2208 } | 2228 } |
2209 }; | 2229 }; |
2210 | 2230 |
2211 /** | 2231 /** |
2212 * Check if all the files in the current selection are available. The only | 2232 * Check if all the files in the current selection are available. The only |
2213 * case when files might be not available is when the selection contains | 2233 * case when files might be not available is when the selection contains |
2214 * uncached GData files and the browser is offline. | 2234 * uncached GData files and the browser is offline. |
2215 * @return {boolean} True if all files in the current selection are | 2235 * @return {boolean} True if all files in the current selection are |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2334 setVisibility('visible'); | 2354 setVisibility('visible'); |
2335 self.previewThumbnails_.textContent = ''; | 2355 self.previewThumbnails_.textContent = ''; |
2336 self.onResize_(); | 2356 self.onResize_(); |
2337 } | 2357 } |
2338 | 2358 |
2339 function setVisibility(visibility) { | 2359 function setVisibility(visibility) { |
2340 panel.setAttribute('visibility', visibility); | 2360 panel.setAttribute('visibility', visibility); |
2341 } | 2361 } |
2342 }; | 2362 }; |
2343 | 2363 |
2344 FileManager.prototype.isGDataEnabled = function() { | |
2345 return this.getGDataPreferences_().driveEnabled; | |
2346 }; | |
2347 | |
2348 FileManager.prototype.updateGDataAccess_ = function() { | |
2349 if (this.isGDataEnabled()) | |
2350 this.setupGDataWelcome_(); | |
2351 else | |
2352 this.cleanupGDataWelcome_(); | |
2353 | |
2354 var changeDirectory = !this.isGDataEnabled() && this.isOnGData(); | |
2355 | |
2356 this.directoryModel_.updateRoots(function() { | |
2357 if (changeDirectory) | |
2358 this.directoryModel_.changeDirectory( | |
2359 this.directoryModel_.getDefaultDirectory()); | |
2360 }.bind(this), this.getGDataAccessMode_()); | |
2361 }; | |
2362 | |
2363 FileManager.prototype.getGDataAccessMode_ = function() { | |
2364 if (!this.isGDataEnabled()) | |
2365 return DirectoryModel.GDATA_ACCESS_DISABLED; | |
2366 if (!this.gdataMounted_) | |
2367 return DirectoryModel.GDATA_ACCESS_LAZY; | |
2368 return DirectoryModel.GDATA_ACCESS_FULL; | |
2369 }; | |
2370 | |
2371 FileManager.prototype.isOnGData = function() { | 2364 FileManager.prototype.isOnGData = function() { |
2372 return this.directoryModel_ && | 2365 return this.directoryModel_.getCurrentRootType() == |
2373 this.directoryModel_.getCurrentRootPath() == | 2366 DirectoryModel.RootType.GDATA; |
2374 '/' + DirectoryModel.GDATA_DIRECTORY; | |
2375 }; | |
2376 | |
2377 FileManager.prototype.isStartingOnGData_ = function() { | |
2378 var path = this.getPathFromUrlOrParams_(); | |
2379 return path && | |
2380 this.isGDataEnabled() && | |
2381 DirectoryModel.getRootType(path) == DirectoryModel.RootType.GDATA; | |
2382 }; | 2367 }; |
2383 | 2368 |
2384 FileManager.prototype.getMetadataProvider = function() { | 2369 FileManager.prototype.getMetadataProvider = function() { |
2385 return this.metadataProvider_; | 2370 return this.metadataProvider_; |
2386 }; | 2371 }; |
2387 | 2372 |
2388 /** | 2373 /** |
2389 * Callback called when tasks for selected files are determined. | 2374 * Callback called when tasks for selected files are determined. |
2390 * @param {Object} selection Selection is passed here, since this.selection | 2375 * @param {Object} selection Selection is passed here, since this.selection |
2391 * can change before tasks were found, and we should be accurate. | 2376 * can change before tasks were found, and we should be accurate. |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2603 }.bind(this)); | 2588 }.bind(this)); |
2604 return; | 2589 return; |
2605 } | 2590 } |
2606 callback(urls); | 2591 callback(urls); |
2607 }.bind(this)); | 2592 }.bind(this)); |
2608 } else { | 2593 } else { |
2609 callback(urls); | 2594 callback(urls); |
2610 } | 2595 } |
2611 }; | 2596 }; |
2612 | 2597 |
2613 FileManager.prototype.getGDataPreferences_ = function() { | 2598 FileManager.prototype.updateNetworkStateAndGDataPreferences_ = function( |
2614 return this.gdataPreferences_ || | 2599 callback) { |
2615 { driveEnabled: str('ENABLE_GDATA') == '1' }; | 2600 var self = this; |
| 2601 var downcount = 2; |
| 2602 function done() { |
| 2603 if (--downcount == 0) |
| 2604 callback(); |
| 2605 } |
| 2606 |
| 2607 chrome.fileBrowserPrivate.getGDataPreferences(function(prefs) { |
| 2608 self.gdataPreferences_ = prefs; |
| 2609 done(); |
| 2610 }); |
| 2611 |
| 2612 chrome.fileBrowserPrivate.getNetworkConnectionState(function(netwokState) { |
| 2613 self.networkState_ = netwokState; |
| 2614 done(); |
| 2615 }); |
2616 }; | 2616 }; |
2617 | 2617 |
2618 FileManager.prototype.getNetworkConnectionState_ = function() { | 2618 FileManager.prototype.onNetworkStateOrGDataPreferencesChanged_ = function() { |
2619 return this.networkConnectionState_ || {}; | 2619 var self = this; |
2620 }; | 2620 this.updateNetworkStateAndGDataPreferences_(function() { |
| 2621 var gdata = self.gdataPreferences_; |
| 2622 var network = self.networkState_; |
2621 | 2623 |
2622 FileManager.prototype.onNetworkConnectionChanged_ = function(state) { | 2624 self.directoryModel_.setGDataEnabled(self.isGDataEnabled()); |
2623 console.log(state.online ? 'online' : 'offline', state.type); | |
2624 this.networkConnectionState_ = state; | |
2625 this.directoryModel_.setOffline(!state.online); | |
2626 this.updateConnectionState_(); | |
2627 }; | |
2628 | 2625 |
2629 FileManager.prototype.onGDataPreferencesChanged_ = function(preferences) { | 2626 if (self.isGDataEnabled()) |
2630 var gdataWasEnabled = this.isGDataEnabled(); | 2627 self.setupGDataWelcome_(); |
2631 this.gdataPreferences_ = preferences; | 2628 else |
2632 if (gdataWasEnabled != this.isGDataEnabled()) | 2629 self.cleanupGDataWelcome_(); |
2633 this.updateGDataAccess_(); | |
2634 | 2630 |
2635 if (preferences.cellularDisabled) | 2631 if (gdata.cellularDisabled) |
2636 this.syncButton.setAttribute('checked', 'checked'); | 2632 self.syncButton.setAttribute('checked', ''); |
2637 else | 2633 else |
2638 this.syncButton.removeAttribute('checked'); | 2634 self.syncButton.removeAttribute('checked'); |
2639 | 2635 |
2640 if (!preferences.hostedFilesDisabled) | 2636 if (!gdata.hostedFilesDisabled) |
2641 this.hostedButton.setAttribute('checked', 'checked'); | 2637 self.hostedButton.setAttribute('checked', ''); |
2642 else | 2638 else |
2643 this.hostedButton.removeAttribute('checked'); | 2639 self.hostedButton.removeAttribute('checked'); |
2644 | 2640 |
2645 this.updateConnectionState_(); | 2641 if (network.online) { |
2646 }; | 2642 if (gdata.cellularDisabled && network.type == 'cellular') |
2647 | 2643 self.dialogContainer_.setAttribute('connection', 'metered'); |
2648 FileManager.prototype.updateConnectionState_ = function() { | 2644 else |
2649 if (this.isOffline()) | 2645 self.dialogContainer_.removeAttribute('connection'); |
2650 this.dialogContainer_.setAttribute('connection', 'offline'); | 2646 } else { |
2651 else if (this.isOnMeteredConnection()) | 2647 self.dialogContainer_.setAttribute('connection', 'offline'); |
2652 this.dialogContainer_.setAttribute('connection', 'metered'); | 2648 } |
2653 else | 2649 }); |
2654 this.dialogContainer_.removeAttribute('connection'); | |
2655 }; | 2650 }; |
2656 | 2651 |
2657 FileManager.prototype.isOnMeteredConnection = function() { | 2652 FileManager.prototype.isOnMeteredConnection = function() { |
2658 return this.getGDataPreferences_().cellularDisabled && | 2653 return this.gdataPreferences_.cellularDisabled && |
2659 this.getNetworkConnectionState_().online && | 2654 this.networkState_.online && |
2660 this.getNetworkConnectionState_().type == 'cellular'; | 2655 this.networkState_.type == 'cellular'; |
2661 }; | 2656 }; |
2662 | 2657 |
2663 FileManager.prototype.isOffline = function() { | 2658 FileManager.prototype.isOffline = function() { |
2664 return !this.getNetworkConnectionState_().online; | 2659 return !this.networkState_.online; |
| 2660 }; |
| 2661 |
| 2662 FileManager.prototype.isGDataEnabled = function() { |
| 2663 return !('driveEnabled' in this.gdataPreferences_) || |
| 2664 this.gdataPreferences_.driveEnabled; |
2665 }; | 2665 }; |
2666 | 2666 |
2667 FileManager.prototype.isOnReadonlyDirectory = function() { | 2667 FileManager.prototype.isOnReadonlyDirectory = function() { |
2668 return this.directoryModel_.isReadOnly(); | 2668 return this.directoryModel_.isReadOnly(); |
2669 }; | 2669 }; |
2670 | 2670 |
2671 /** | 2671 FileManager.prototype.onUnexpectedlyUnmounted_ = function(event) { |
2672 * Event handler called when some volume was mounted or unmouted. | 2672 if (event.mountPath == this.directoryModel_.getCurrentRootPath()) { |
2673 */ | 2673 if (this.params_.mountTriggered) { |
2674 FileManager.prototype.onMountCompleted_ = function(event) { | 2674 // TODO(serya): What if 2 USB sticks plugged? |
2675 var changeDirectoryTo = null; | 2675 chrome.tabs.getCurrent(function(tab) { |
2676 | 2676 chrome.tabs.remove(tab.id); |
2677 if (event && event.mountType == 'gdata') { | 2677 }); |
2678 var mounted = (event.eventType == 'mount'); | |
2679 metrics.recordInterval('Load.GData'); | |
2680 console.log('GData ' + (mounted ? 'mounted' : 'unmounted')); | |
2681 if (mounted && event.status == 'success') { | |
2682 this.gdataMounted_ = true; | |
2683 this.gdataMountInfo_ = { | |
2684 'mountPath': event.mountPath, | |
2685 'sourcePath': event.sourcePath, | |
2686 'mountType': event.mountType, | |
2687 'mountCondition': event.status | |
2688 }; | |
2689 // Not calling clearGDataLoadingTimer_ here because we want to keep | |
2690 // "Loading Google Docs" message until the directory loads. It is OK if | |
2691 // the timer fires after the mount because onDirectoryChanged_ will hide | |
2692 // the unmounted panel. | |
2693 if (this.setupCurrentDirectoryPostponed_) { | |
2694 this.setupCurrentDirectoryPostponed_(false /* execute */); | |
2695 } else if (this.isOnGData() && | |
2696 this.directoryModel_.getCurrentDirEntry().unmounted) { | |
2697 // We are currently on an unmounted GData directory, force a rescan. | |
2698 changeDirectoryTo = this.directoryModel_.getCurrentRootPath(); | |
2699 } | |
2700 } else { | |
2701 this.onGDataUnreachable_('GData ' + | |
2702 (mounted ? ('mount failed: ' + event.status) : 'unmounted')); | |
2703 if (this.setupCurrentDirectoryPostponed_) { | |
2704 this.setupCurrentDirectoryPostponed_(true /* cancel */); | |
2705 // Change to unmounted GData root. | |
2706 changeDirectoryTo = '/' + DirectoryModel.GDATA_DIRECTORY; | |
2707 } | |
2708 } | 2678 } |
2709 } | 2679 } |
2710 | |
2711 chrome.fileBrowserPrivate.getMountPoints(function(mountPoints) { | |
2712 this.setMountPoints_(mountPoints); | |
2713 | |
2714 if (event.eventType == 'mount' && event.mountType != 'gdata') { | |
2715 // Mount request finished - remove it. | |
2716 // Currently we only request mounts for archive files. | |
2717 var index = this.mountRequests_.indexOf(event.sourcePath); | |
2718 if (index != -1) { | |
2719 this.mountRequests_.splice(index, 1); | |
2720 if (event.status == 'success') { | |
2721 // Successful mount requested from this tab, go to the drive root. | |
2722 changeDirectoryTo = event.mountPath; | |
2723 } else { | |
2724 // Request initiated from this tab failed, report the error. | |
2725 var fileName = event.sourcePath.split('/').pop(); | |
2726 this.alert.show( | |
2727 strf('ARCHIVE_MOUNT_FAILED', fileName, event.status)); | |
2728 } | |
2729 } | |
2730 } | |
2731 | |
2732 if (event.eventType == 'unmount' && event.mountType != 'gdata') { | |
2733 // Unmount request finished - remove it. | |
2734 var index = this.unmountRequests_.indexOf(event.mountPath); | |
2735 if (index != -1) { | |
2736 this.unmountRequests_.splice(index, 1); | |
2737 if (event.status != 'success') | |
2738 this.alert.show(strf('UNMOUNT_FAILED', event.status)); | |
2739 } | |
2740 | |
2741 if (event.status == 'success' && | |
2742 event.mountPath == this.directoryModel_.getCurrentRootPath()) { | |
2743 if (this.params_.mountTriggered && index == -1) { | |
2744 // This device mount was the reason this File Manager instance was | |
2745 // created. Now the device is unmounted from another instance | |
2746 // or the user removed the device manually. Close this instance. | |
2747 // window.close() sometimes doesn't work. | |
2748 chrome.tabs.getCurrent(function(tab) { | |
2749 chrome.tabs.remove(tab.id); | |
2750 }); | |
2751 return; | |
2752 } | |
2753 // Current directory just unmounted. Move to the 'Downloads'. | |
2754 changeDirectoryTo = this.directoryModel_.getDefaultDirectory(); | |
2755 } | |
2756 } | |
2757 | |
2758 // Even if something failed root list should be rescanned. | |
2759 // Failed mounts can "give" us new devices which might be formatted, | |
2760 // so we have to refresh root list then. | |
2761 this.directoryModel_.updateRoots(function() { | |
2762 if (changeDirectoryTo) { | |
2763 this.directoryModel_.changeDirectory(changeDirectoryTo); | |
2764 } | |
2765 }.bind(this), this.getGDataAccessMode_()); | |
2766 }.bind(this)); | |
2767 }; | 2680 }; |
2768 | 2681 |
2769 /** | 2682 /** |
2770 * Event handler called when some internal task should be executed. | 2683 * Event handler called when some internal task should be executed. |
2771 */ | 2684 */ |
2772 FileManager.prototype.onFileTaskExecute_ = function(id, urls) { | 2685 FileManager.prototype.onFileTaskExecute_ = function(id, urls) { |
2773 if (id == 'play') { | 2686 if (id == 'play') { |
2774 var position = 0; | 2687 var position = 0; |
2775 if (urls.length == 1) { | 2688 if (urls.length == 1) { |
2776 // If just a single audio file is selected pass along every audio file | 2689 // If just a single audio file is selected pass along every audio file |
2777 // in the directory. | 2690 // in the directory. |
2778 var selectedUrl = urls[0]; | 2691 var selectedUrl = urls[0]; |
2779 urls = this.getAllUrlsInCurrentDirectory_().filter(FileType.isAudio); | 2692 urls = this.getAllUrlsInCurrentDirectory_().filter(FileType.isAudio); |
2780 position = urls.indexOf(selectedUrl); | 2693 position = urls.indexOf(selectedUrl); |
2781 } | 2694 } |
2782 chrome.mediaPlayerPrivate.play(urls, position); | 2695 chrome.mediaPlayerPrivate.play(urls, position); |
2783 } else if (id == 'mount-archive') { | 2696 } else if (id == 'mount-archive') { |
2784 var self = this; | 2697 var self = this; |
| 2698 var tracker = this.directoryModel_.createDirectoryChangeTracker(); |
| 2699 tracker.start(); |
2785 this.resolveSelectResults_(urls, function(urls) { | 2700 this.resolveSelectResults_(urls, function(urls) { |
2786 for (var index = 0; index < urls.length; ++index) { | 2701 for (var index = 0; index < urls.length; ++index) { |
2787 // Url in MountCompleted event won't be escaped, so let's make sure | 2702 var path = /^filesystem:[\w-]*:\/\/[\w]*\/external(\/.*)$/. |
2788 // we don't use escaped one in mountRequests_. | 2703 exec(urls[index])[1]; |
2789 var unescapedUrl = unescape(urls[index]); | 2704 if (!path) |
2790 chrome.fileBrowserPrivate.addMount(unescapedUrl, 'file', {}, | 2705 continue; |
2791 function(sourcePath) { | 2706 path = decodeURIComponent(path); |
2792 self.mountRequests_.push(sourcePath); | 2707 self.volumeManager_.mountArchive(path, function(mountPath) { |
| 2708 console.log('Mounted at: ', mountPath); |
| 2709 tracker.stop(); |
| 2710 if (!tracker.hasChanged) |
| 2711 self.directoryModel_.changeDirectory(mountPath); |
| 2712 }, function(error) { |
| 2713 tracker.stop(); |
| 2714 var namePos = path.lastIndexOf('/'); |
| 2715 self.alert.show(strf('ARCHIVE_MOUNT_FAILED', |
| 2716 path.substr(namePos + 1), error)); |
2793 }); | 2717 }); |
2794 } | 2718 } |
2795 }); | 2719 }); |
2796 } else if (id == 'format-device') { | 2720 } else if (id == 'format-device') { |
2797 this.confirm.show(str('FORMATTING_WARNING'), function() { | 2721 this.confirm.show(str('FORMATTING_WARNING'), function() { |
2798 chrome.fileBrowserPrivate.formatDevice(urls[0]); | 2722 chrome.fileBrowserPrivate.formatDevice(urls[0]); |
2799 }); | 2723 }); |
2800 } else if (id == 'gallery') { | 2724 } else if (id == 'gallery') { |
2801 this.openGallery_(urls); | 2725 this.openGallery_(urls); |
2802 } else if (id == 'view-pdf' || id == 'view-in-browser' || | 2726 } else if (id == 'view-pdf' || id == 'view-in-browser' || |
2803 id == 'install-crx' || id == 'open-hosted') { | 2727 id == 'install-crx' || id == 'open-hosted') { |
2804 chrome.fileBrowserPrivate.viewFiles(urls, 'default', function(success) { | 2728 chrome.fileBrowserPrivate.viewFiles(urls, 'default', function(success) { |
2805 if (!success) | 2729 if (!success) |
2806 console.error('chrome.fileBrowserPrivate.viewFiles failed', urls); | 2730 console.error('chrome.fileBrowserPrivate.viewFiles failed', urls); |
2807 }); | 2731 }); |
2808 } | 2732 } |
2809 }; | 2733 }; |
2810 | 2734 |
2811 FileManager.prototype.getDeviceNumber = function(entry) { | |
2812 if (!entry.isDirectory) return undefined; | |
2813 for (var i = 0; i < this.mountPoints_.length; i++) { | |
2814 if (normalizeAbsolutePath(entry.fullPath) == | |
2815 normalizeAbsolutePath(this.mountPoints_[i].mountPath)) { | |
2816 return i; | |
2817 } | |
2818 } | |
2819 return undefined; | |
2820 }; | |
2821 | |
2822 /** | 2735 /** |
2823 * Show a modal-like file viewer/editor on top of the File Manager UI. | 2736 * Show a modal-like file viewer/editor on top of the File Manager UI. |
2824 * | 2737 * |
2825 * @param {HTMLElement} popup Popup element. | 2738 * @param {HTMLElement} popup Popup element. |
2826 * @param {function} closeCallback Function to call after the popup is closed. | 2739 * @param {function} closeCallback Function to call after the popup is closed. |
2827 */ | 2740 */ |
2828 FileManager.prototype.openFilePopup_ = function(popup, closeCallback) { | 2741 FileManager.prototype.openFilePopup_ = function(popup, closeCallback) { |
2829 this.closeFilePopup_(); | 2742 this.closeFilePopup_(); |
2830 this.filePopup_ = popup; | 2743 this.filePopup_ = popup; |
2831 this.filePopupCloseCallback_ = closeCallback; | 2744 this.filePopupCloseCallback_ = closeCallback; |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2922 galleryFrame.className = 'overlay-pane'; | 2835 galleryFrame.className = 'overlay-pane'; |
2923 galleryFrame.scrolling = 'no'; | 2836 galleryFrame.scrolling = 'no'; |
2924 galleryFrame.setAttribute('webkitallowfullscreen', true); | 2837 galleryFrame.setAttribute('webkitallowfullscreen', true); |
2925 | 2838 |
2926 var dirPath = this.directoryModel_.getCurrentDirEntry().fullPath; | 2839 var dirPath = this.directoryModel_.getCurrentDirEntry().fullPath; |
2927 // Push a temporary state which will be replaced every time an individual | 2840 // Push a temporary state which will be replaced every time an individual |
2928 // item is selected in the Gallery. | 2841 // item is selected in the Gallery. |
2929 this.updateLocation_(false /*push*/, dirPath); | 2842 this.updateLocation_(false /*push*/, dirPath); |
2930 | 2843 |
2931 galleryFrame.onload = function() { | 2844 galleryFrame.onload = function() { |
| 2845 self.show_(); |
2932 galleryFrame.contentWindow.ImageUtil.metrics = metrics; | 2846 galleryFrame.contentWindow.ImageUtil.metrics = metrics; |
2933 galleryFrame.contentWindow.FileType = FileType; | 2847 galleryFrame.contentWindow.FileType = FileType; |
2934 galleryFrame.contentWindow.util = util; | 2848 galleryFrame.contentWindow.util = util; |
2935 | 2849 |
2936 // Gallery shoud treat GData folder as readonly even when online | 2850 // Gallery shoud treat GData folder as readonly even when online |
2937 // until we learn to save files directly to GData. | 2851 // until we learn to save files directly to GData. |
2938 var readonly = self.isOnReadonlyDirectory() || self.isOnGData(); | 2852 var readonly = self.isOnReadonlyDirectory() || self.isOnGData(); |
2939 var currentDir = self.directoryModel_.getCurrentDirEntry(); | 2853 var currentDir = self.directoryModel_.getCurrentDirEntry(); |
2940 var downloadsDir = self.directoryModel_.getRootsList().item(0); | 2854 var downloadsDir = self.directoryModel_.getRootsList().item(0); |
2941 | 2855 |
(...skipping 29 matching lines...) Expand all Loading... |
2971 }; | 2885 }; |
2972 | 2886 |
2973 /** | 2887 /** |
2974 * Update the breadcrumb display to reflect the current directory. | 2888 * Update the breadcrumb display to reflect the current directory. |
2975 */ | 2889 */ |
2976 FileManager.prototype.updateBreadcrumbs_ = function() { | 2890 FileManager.prototype.updateBreadcrumbs_ = function() { |
2977 var bc = this.dialogDom_.querySelector('.breadcrumbs'); | 2891 var bc = this.dialogDom_.querySelector('.breadcrumbs'); |
2978 removeChildren(bc); | 2892 removeChildren(bc); |
2979 | 2893 |
2980 var rootPath = this.directoryModel_.getCurrentRootPath(); | 2894 var rootPath = this.directoryModel_.getCurrentRootPath(); |
2981 var relativePath = this.directoryModel_.getCurrentDirEntry().fullPath. | 2895 var relativePath = this.directoryModel_.getCurrentDirPath(). |
2982 substring(rootPath.length).replace(/\/$/, ''); | 2896 substring(rootPath.length).replace(/\/$/, ''); |
2983 | 2897 |
2984 var pathNames = relativePath.replace(/\/$/, '').split('/'); | 2898 var pathNames = relativePath.replace(/\/$/, '').split('/'); |
2985 if (pathNames[0] == '') | 2899 if (pathNames[0] == '') |
2986 pathNames.splice(0, 1); | 2900 pathNames.splice(0, 1); |
2987 | 2901 |
2988 // We need a first breadcrumb for root, so placing last name from | 2902 // We need a first breadcrumb for root, so placing last name from |
2989 // rootPath as first name of relativePath. | 2903 // rootPath as first name of relativePath. |
2990 var rootPathNames = rootPath.replace(/\/$/, '').split('/'); | 2904 var rootPathNames = rootPath.replace(/\/$/, '').split('/'); |
2991 pathNames.splice(0, 0, rootPathNames[rootPathNames.length - 1]); | 2905 pathNames.splice(0, 0, rootPathNames[rootPathNames.length - 1]); |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3143 this.table_.focus(); | 3057 this.table_.focus(); |
3144 else // this.listType_ == FileManager.ListType.THUMBNAIL) | 3058 else // this.listType_ == FileManager.ListType.THUMBNAIL) |
3145 this.grid_.focus(); | 3059 this.grid_.focus(); |
3146 }; | 3060 }; |
3147 | 3061 |
3148 /** | 3062 /** |
3149 * Return full path of the current directory or null. | 3063 * Return full path of the current directory or null. |
3150 */ | 3064 */ |
3151 FileManager.prototype.getCurrentDirectory = function() { | 3065 FileManager.prototype.getCurrentDirectory = function() { |
3152 return this.directoryModel_ && | 3066 return this.directoryModel_ && |
3153 this.directoryModel_.getCurrentDirEntry().fullPath; | 3067 this.directoryModel_.getCurrentDirPath(); |
3154 }; | 3068 }; |
3155 | 3069 |
3156 /** | 3070 /** |
3157 * Return URL of the current directory or null. | 3071 * Return URL of the current directory or null. |
3158 */ | 3072 */ |
3159 FileManager.prototype.getCurrentDirectoryURL = function() { | 3073 FileManager.prototype.getCurrentDirectoryURL = function() { |
3160 return this.directoryModel_ && | 3074 return this.directoryModel_ && |
3161 this.directoryModel_.getCurrentDirEntry().toURL(); | 3075 this.directoryModel_.getCurrentDirEntry().toURL(); |
3162 }; | 3076 }; |
3163 | 3077 |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3455 | 3369 |
3456 /** | 3370 /** |
3457 * Executes directory action (i.e. changes directory). If new directory is a | 3371 * Executes directory action (i.e. changes directory). If new directory is a |
3458 * search result directory, we'll have to calculate its real path before we | 3372 * search result directory, we'll have to calculate its real path before we |
3459 * actually do the operation. | 3373 * actually do the operation. |
3460 * | 3374 * |
3461 * @param {DirectoryEntry} entry Directory entry to which directory should be | 3375 * @param {DirectoryEntry} entry Directory entry to which directory should be |
3462 * changed. | 3376 * changed. |
3463 */ | 3377 */ |
3464 FileManager.prototype.onDirectoryAction = function(entry) { | 3378 FileManager.prototype.onDirectoryAction = function(entry) { |
| 3379 var mountError = this.volumeManager_.getMountError( |
| 3380 DirectoryModel.getRootPath(entry.fullPath)); |
| 3381 if (mountError == VolumeManager.Error.UNKNOWN_FILESYSTEM) { |
| 3382 return this.showButter(str('UNKNOWN_FILESYSTEM_WARNING')); |
| 3383 } else if (mountError == VolumeManager.Error.UNSUPPORTED_FILESYSTEM) { |
| 3384 return this.showButter(str('UNSUPPORTED_FILESYSTEM_WARNING')); |
| 3385 } |
3465 if (!DirectoryModel.isGDataSearchPath(entry.fullPath)) | 3386 if (!DirectoryModel.isGDataSearchPath(entry.fullPath)) |
3466 return this.directoryModel_.changeDirectory(entry.fullPath); | 3387 return this.directoryModel_.changeDirectory(entry.fullPath); |
3467 | 3388 |
3468 // If we are under gdata search path, the real entries file path may be | 3389 // If we are under gdata search path, the real entries file path may be |
3469 // different from |entry.fullPath|. | 3390 // different from |entry.fullPath|. |
3470 var self = this; | 3391 var self = this; |
3471 chrome.fileBrowserPrivate.getPathForDriveSearchResult(entry.toURL(), | 3392 chrome.fileBrowserPrivate.getPathForDriveSearchResult(entry.toURL(), |
3472 function(path) { | 3393 function(path) { |
3473 // |path| may be undefined if there was an error. If that is the case, | 3394 // |path| may be undefined if there was an error. If that is the case, |
3474 // change to the original file path. | 3395 // change to the original file path. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3538 * | 3459 * |
3539 * @param {cr.Event} event The directory-changed event. | 3460 * @param {cr.Event} event The directory-changed event. |
3540 */ | 3461 */ |
3541 FileManager.prototype.onDirectoryChanged_ = function(event) { | 3462 FileManager.prototype.onDirectoryChanged_ = function(event) { |
3542 this.updateCommonActionButtons_(); | 3463 this.updateCommonActionButtons_(); |
3543 this.updateOkButton_(); | 3464 this.updateOkButton_(); |
3544 this.updateBreadcrumbs_(); | 3465 this.updateBreadcrumbs_(); |
3545 this.updateColumnModel_(); | 3466 this.updateColumnModel_(); |
3546 this.updateSearchBoxOnDirChange_(); | 3467 this.updateSearchBoxOnDirChange_(); |
3547 | 3468 |
3548 // Sometimes we rescan the same directory (when mounting GData lazily first, | 3469 this.updateLocation_(event.initial, this.getCurrentDirectory()); |
3549 // then for real). Do not update the location then. | |
3550 if (event.newDirEntry.fullPath != event.previousDirEntry.fullPath) { | |
3551 this.updateLocation_(event.initial, event.newDirEntry.fullPath); | |
3552 } | |
3553 | |
3554 this.checkFreeSpace_(this.getCurrentDirectory()); | 3470 this.checkFreeSpace_(this.getCurrentDirectory()); |
3555 | 3471 |
3556 this.updateTitle_(); | 3472 this.updateTitle_(); |
3557 | 3473 this.updateGDataUnmountedPanel_(); |
3558 if (this.filesystemObserverId_) | 3474 if (this.isOnGData()) |
3559 this.metadataCache_.removeObserver(this.filesystemObserverId_); | 3475 this.unmountedPanel_.classList.remove('retry-enabled'); |
3560 if (this.gdataObserverId_) | |
3561 this.metadataCache_.removeObserver(this.gdataObserverId_); | |
3562 | |
3563 this.filesystemObserverId_ = this.metadataCache_.addObserver( | |
3564 this.directoryModel_.getCurrentDirEntry(), | |
3565 MetadataCache.CHILDREN, | |
3566 'filesystem', | |
3567 this.updateMetadataInUI_.bind(this, 'filesystem')); | |
3568 | |
3569 if (this.isOnGData()) { | |
3570 this.gdataObserverId_ = this.metadataCache_.addObserver( | |
3571 this.directoryModel_.getCurrentDirEntry(), | |
3572 MetadataCache.CHILDREN, | |
3573 'gdata', | |
3574 this.updateMetadataInUI_.bind(this, 'gdata')); | |
3575 } | |
3576 | |
3577 var self = this; | |
3578 | |
3579 if (this.watchedDirectoryUrl_) { | |
3580 if (this.watchedDirectoryUrl_ != event.previousDirEntry.toURL()) { | |
3581 console.warn('event.previousDirEntry does not match File Manager state', | |
3582 event, this.watchedDirectoryUrl_); | |
3583 } | |
3584 chrome.fileBrowserPrivate.removeFileWatch(this.watchedDirectoryUrl_, | |
3585 function(result) { | |
3586 if (!result) { | |
3587 console.log('Failed to remove file watch'); | |
3588 } | |
3589 }); | |
3590 this.watchedDirectoryUrl_ = null; | |
3591 } | |
3592 | |
3593 if (event.newDirEntry.fullPath != '/' && !event.newDirEntry.unmounted) { | |
3594 this.watchedDirectoryUrl_ = event.newDirEntry.toURL(); | |
3595 chrome.fileBrowserPrivate.addFileWatch(this.watchedDirectoryUrl_, | |
3596 function(result) { | |
3597 if (!result) { | |
3598 console.log('Failed to add file watch'); | |
3599 this.watchedDirectoryUrl_ = null; | |
3600 } | |
3601 }.bind(this)); | |
3602 } | |
3603 | |
3604 if (event.newDirEntry.unmounted) | |
3605 this.dialogContainer_.setAttribute('unmounted', true); | |
3606 else { | |
3607 this.dialogContainer_.removeAttribute('unmounted'); | |
3608 // Need to resize explicitly because the list container had display:none. | |
3609 this.onResize_(); | |
3610 } | |
3611 | |
3612 if (this.isOnGData()) { | |
3613 this.dialogContainer_.setAttribute('gdata', true); | |
3614 if (event.newDirEntry.unmounted) { | |
3615 if (event.newDirEntry.error) | |
3616 this.onGDataUnreachable_('File error ' + event.newDirEntry.error); | |
3617 else | |
3618 this.initGData_(true /* directory changed */); | |
3619 } | |
3620 } else { | |
3621 this.dialogContainer_.removeAttribute('gdata'); | |
3622 } | |
3623 }; | 3476 }; |
3624 | 3477 |
3625 FileManager.prototype.findListItemForEvent_ = function(event) { | 3478 FileManager.prototype.findListItemForEvent_ = function(event) { |
3626 return this.findListItemForNode_(event.srcElement); | 3479 return this.findListItemForNode_(event.srcElement); |
3627 }; | 3480 }; |
3628 | 3481 |
3629 FileManager.prototype.findListItemForNode_ = function(node) { | 3482 FileManager.prototype.findListItemForNode_ = function(node) { |
3630 var item = this.currentList_.getListItemAncestor(node); | 3483 var item = this.currentList_.getListItemAncestor(node); |
3631 // TODO(serya): list should check that. | 3484 // TODO(serya): list should check that. |
3632 return item && this.currentList_.isItem(item) ? item : null; | 3485 return item && this.currentList_.isItem(item) ? item : null; |
3633 }; | 3486 }; |
3634 | 3487 |
3635 /** | 3488 /** |
3636 * Unload handler for the page. May be called manually for the file picker | 3489 * Unload handler for the page. May be called manually for the file picker |
3637 * dialog, because it closes by calling extension API functions that do not | 3490 * dialog, because it closes by calling extension API functions that do not |
3638 * return. | 3491 * return. |
3639 */ | 3492 */ |
3640 FileManager.prototype.onUnload_ = function() { | 3493 FileManager.prototype.onUnload_ = function() { |
3641 if (this.watchedDirectoryUrl_) { | 3494 this.fileWatcher_.stop(); |
3642 chrome.fileBrowserPrivate.removeFileWatch( | |
3643 this.watchedDirectoryUrl_, | |
3644 function(result) { | |
3645 if (!result) { | |
3646 console.log('Failed to remove file watch'); | |
3647 } | |
3648 }); | |
3649 this.watchedDirectoryUrl_ = null; | |
3650 } | |
3651 }; | |
3652 | |
3653 FileManager.prototype.onFileChanged_ = function(event) { | |
3654 // We receive a lot of events even in folders we are not interested in. | |
3655 if (encodeURI(event.fileUrl) == this.getSearchOrCurrentDirectoryURL()) | |
3656 this.directoryModel_.rescanLater(); | |
3657 }; | 3495 }; |
3658 | 3496 |
3659 FileManager.prototype.initiateRename_ = function() { | 3497 FileManager.prototype.initiateRename_ = function() { |
3660 var item = this.currentList_.ensureLeadItemExists(); | 3498 var item = this.currentList_.ensureLeadItemExists(); |
3661 if (!item) | 3499 if (!item) |
3662 return; | 3500 return; |
3663 var label = item.querySelector('.filename-label'); | 3501 var label = item.querySelector('.filename-label'); |
3664 var input = this.renameInput_; | 3502 var input = this.renameInput_; |
3665 | 3503 |
3666 input.value = label.textContent; | 3504 input.value = label.textContent; |
(...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4497 handleSplitterDragEnd: function(e) { | 4335 handleSplitterDragEnd: function(e) { |
4498 Splitter.prototype.handleSplitterDragEnd.apply(this, arguments); | 4336 Splitter.prototype.handleSplitterDragEnd.apply(this, arguments); |
4499 this.ownerDocument.documentElement.classList.remove('col-resize'); | 4337 this.ownerDocument.documentElement.classList.remove('col-resize'); |
4500 } | 4338 } |
4501 }; | 4339 }; |
4502 | 4340 |
4503 customSplitter.decorate(splitterElement); | 4341 customSplitter.decorate(splitterElement); |
4504 }; | 4342 }; |
4505 | 4343 |
4506 FileManager.prototype.setupGDataWelcome_ = function() { | 4344 FileManager.prototype.setupGDataWelcome_ = function() { |
| 4345 if (this.gdataWelcomeHandler_) |
| 4346 return; |
4507 this.gdataWelcomeHandler_ = this.createGDataWelcomeHandler_(); | 4347 this.gdataWelcomeHandler_ = this.createGDataWelcomeHandler_(); |
4508 if (this.gdataWelcomeHandler_) { | 4348 if (this.gdataWelcomeHandler_) { |
4509 this.directoryModel_.addEventListener('scan-completed', | 4349 this.directoryModel_.addEventListener('scan-completed', |
4510 this.gdataWelcomeHandler_); | 4350 this.gdataWelcomeHandler_); |
4511 this.directoryModel_.addEventListener('rescan-completed', | 4351 this.directoryModel_.addEventListener('rescan-completed', |
4512 this.gdataWelcomeHandler_); | 4352 this.gdataWelcomeHandler_); |
4513 } | 4353 } |
4514 }; | 4354 }; |
4515 | 4355 |
4516 FileManager.prototype.cleanupGDataWelcome_ = function() { | 4356 FileManager.prototype.cleanupGDataWelcome_ = function() { |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4626 | 4466 |
4627 function closeBanner() { | 4467 function closeBanner() { |
4628 self.cleanupGDataWelcome_(); | 4468 self.cleanupGDataWelcome_(); |
4629 // Stop showing the welcome banner. | 4469 // Stop showing the welcome banner. |
4630 localStorage[WELCOME_HEADER_COUNTER_KEY] = WELCOME_HEADER_COUNTER_LIMIT; | 4470 localStorage[WELCOME_HEADER_COUNTER_KEY] = WELCOME_HEADER_COUNTER_LIMIT; |
4631 } | 4471 } |
4632 | 4472 |
4633 return maybeShowBanner; | 4473 return maybeShowBanner; |
4634 }; | 4474 }; |
4635 })(); | 4475 })(); |
| 4476 |
OLD | NEW |