| 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 // If directory files changes too often, don't rescan directory more than once | 5 // If directory files changes too often, don't rescan directory more than once |
| 6 // per specified interval | 6 // per specified interval |
| 7 var SIMULTANEOUS_RESCAN_INTERVAL = 1000; | 7 var SIMULTANEOUS_RESCAN_INTERVAL = 1000; |
| 8 // Used for operations that require almost instant rescan. | 8 // Used for operations that require almost instant rescan. |
| 9 var SHORT_RESCAN_INTERVAL = 100; | 9 var SHORT_RESCAN_INTERVAL = 100; |
| 10 | 10 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 | 48 |
| 49 // The map 'name' -> callback. Callbacks are function(entry) -> boolean. | 49 // The map 'name' -> callback. Callbacks are function(entry) -> boolean. |
| 50 this.filters_ = {}; | 50 this.filters_ = {}; |
| 51 this.setFilterHidden(true); | 51 this.setFilterHidden(true); |
| 52 | 52 |
| 53 /** | 53 /** |
| 54 * @private | 54 * @private |
| 55 * @type {Object.<string, boolean>} | 55 * @type {Object.<string, boolean>} |
| 56 */ | 56 */ |
| 57 this.volumeReadOnlyStatus_ = {}; | 57 this.volumeReadOnlyStatus_ = {}; |
| 58 |
| 59 /** |
| 60 * Directory in which search results are displayed. Not null iff search |
| 61 * results are being displayed. |
| 62 * @private |
| 63 * @type {Entry} |
| 64 */ |
| 65 this.searchDirEntry_ = null; |
| 66 |
| 67 /** |
| 68 * Is search in progress. |
| 69 * @private |
| 70 * @type {boolean} |
| 71 */ |
| 72 this.isSearching_ = false; |
| 58 } | 73 } |
| 59 | 74 |
| 60 /** | 75 /** |
| 61 * The name of the directory containing externally | 76 * The name of the directory containing externally |
| 62 * mounted removable storage volumes. | 77 * mounted removable storage volumes. |
| 63 */ | 78 */ |
| 64 DirectoryModel.REMOVABLE_DIRECTORY = 'removable'; | 79 DirectoryModel.REMOVABLE_DIRECTORY = 'removable'; |
| 65 | 80 |
| 66 /** | 81 /** |
| 67 * The name of the directory containing externally | 82 * The name of the directory containing externally |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 99 * GData access mode: lazy (GData root displayed, no content is fetched yet). | 114 * GData access mode: lazy (GData root displayed, no content is fetched yet). |
| 100 */ | 115 */ |
| 101 DirectoryModel.GDATA_ACCESS_LAZY = 1; | 116 DirectoryModel.GDATA_ACCESS_LAZY = 1; |
| 102 | 117 |
| 103 /** | 118 /** |
| 104 * GData access mode: full (GData root displayed, content is available). | 119 * GData access mode: full (GData root displayed, content is available). |
| 105 */ | 120 */ |
| 106 DirectoryModel.GDATA_ACCESS_FULL = 2; | 121 DirectoryModel.GDATA_ACCESS_FULL = 2; |
| 107 | 122 |
| 108 /** | 123 /** |
| 124 * Root path used for displaying gdata content search results. |
| 125 * Search results will be shown in directory 'GDATA_SEARCH_ROOT_PATH/query'. |
| 126 * |
| 127 * @const |
| 128 * @type {string} |
| 129 */ |
| 130 DirectoryModel.GDATA_SEARCH_ROOT_PATH = '/drive/.search'; |
| 131 |
| 132 /** |
| 133 * @const |
| 134 * @type {Array.<string>} |
| 135 */ |
| 136 DirectoryModel.GDATA_SEARCH_ROOT_COMPONENTS = ['', 'drive', '.search']; |
| 137 |
| 138 /** |
| 109 * DirectoryModel extends cr.EventTarget. | 139 * DirectoryModel extends cr.EventTarget. |
| 110 */ | 140 */ |
| 111 DirectoryModel.prototype.__proto__ = cr.EventTarget.prototype; | 141 DirectoryModel.prototype.__proto__ = cr.EventTarget.prototype; |
| 112 | 142 |
| 113 /** | 143 /** |
| 114 * @return {cr.ui.ArrayDataModel} Files in the current directory. | 144 * @return {cr.ui.ArrayDataModel} Files in the current directory. |
| 115 */ | 145 */ |
| 116 DirectoryModel.prototype.getFileList = function() { | 146 DirectoryModel.prototype.getFileList = function() { |
| 117 return this.fileList_; | 147 return this.fileList_; |
| 118 }; | 148 }; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 }; | 200 }; |
| 171 | 201 |
| 172 /** | 202 /** |
| 173 * @return {boolean} True if current directory is read only. | 203 * @return {boolean} True if current directory is read only. |
| 174 */ | 204 */ |
| 175 DirectoryModel.prototype.isReadOnly = function() { | 205 DirectoryModel.prototype.isReadOnly = function() { |
| 176 return this.isPathReadOnly(this.getCurrentRootPath()); | 206 return this.isPathReadOnly(this.getCurrentRootPath()); |
| 177 }; | 207 }; |
| 178 | 208 |
| 179 /** | 209 /** |
| 180 * @param {string} path Path to check. | 210 * @return {boolean} True if search is in progress. |
| 211 */ |
| 212 DirectoryModel.prototype.isSearching = function() { |
| 213 return this.isSearching_; |
| 214 }; |
| 215 |
| 216 /** |
| 217 * @return {boolean} True if we are currently showing search results. |
| 218 */ |
| 219 DirectoryModel.prototype.isOnGDataSearchDir = function() { |
| 220 return this.getSearchOrCurrentDirEntry() != this.getCurrentDirEntry(); |
| 221 }; |
| 222 |
| 223 /** |
| 224 * @param {strin} path Path to check. |
| 181 * @return {boolean} True if the |path| is read only. | 225 * @return {boolean} True if the |path| is read only. |
| 182 */ | 226 */ |
| 183 DirectoryModel.prototype.isPathReadOnly = function(path) { | 227 DirectoryModel.prototype.isPathReadOnly = function(path) { |
| 184 switch (DirectoryModel.getRootType(path)) { | 228 switch (DirectoryModel.getRootType(path)) { |
| 185 case DirectoryModel.RootType.REMOVABLE: | 229 case DirectoryModel.RootType.REMOVABLE: |
| 186 return !!this.volumeReadOnlyStatus_[DirectoryModel.getRootPath(path)]; | 230 return !!this.volumeReadOnlyStatus_[DirectoryModel.getRootPath(path)]; |
| 187 case DirectoryModel.RootType.ARCHIVE: | 231 case DirectoryModel.RootType.ARCHIVE: |
| 188 return true; | 232 return true; |
| 189 case DirectoryModel.RootType.DOWNLOADS: | 233 case DirectoryModel.RootType.DOWNLOADS: |
| 190 return false; | 234 return false; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 215 }; | 259 }; |
| 216 | 260 |
| 217 /** | 261 /** |
| 218 * @return {DirectoryEntry} Current directory. | 262 * @return {DirectoryEntry} Current directory. |
| 219 */ | 263 */ |
| 220 DirectoryModel.prototype.getCurrentDirEntry = function() { | 264 DirectoryModel.prototype.getCurrentDirEntry = function() { |
| 221 return this.currentDirEntry_; | 265 return this.currentDirEntry_; |
| 222 }; | 266 }; |
| 223 | 267 |
| 224 /** | 268 /** |
| 269 * If search results are being displayed, returns search directory, else returns |
| 270 * current directory. |
| 271 * |
| 272 * @return {DirectoryEntry} search or directory entry. |
| 273 */ |
| 274 DirectoryModel.prototype.getSearchOrCurrentDirEntry = function() { |
| 275 return this.searchDirEntry_ || this.currentDirEntry_; |
| 276 }; |
| 277 |
| 278 /** |
| 225 * @return {string} Path for the current directory. | 279 * @return {string} Path for the current directory. |
| 226 */ | 280 */ |
| 227 DirectoryModel.prototype.getCurrentDirPath = function() { | 281 DirectoryModel.prototype.getCurrentDirPath = function() { |
| 228 return this.currentDirEntry_.fullPath; | 282 return this.currentDirEntry_.fullPath; |
| 229 }; | 283 }; |
| 230 | 284 |
| 231 /** | 285 /** |
| 232 * @private | 286 * @private |
| 233 * @return {Array.<string>} Names of selected files. | 287 * @return {Array.<string>} Names of selected files. |
| 234 */ | 288 */ |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 DirectoryModel.prototype.addFilter = function(name, filter) { | 383 DirectoryModel.prototype.addFilter = function(name, filter) { |
| 330 this.filters_[name] = filter; | 384 this.filters_[name] = filter; |
| 331 this.rescanSoon(); | 385 this.rescanSoon(); |
| 332 }; | 386 }; |
| 333 | 387 |
| 334 /** | 388 /** |
| 335 * Remove one of the directory contents filters, specified by name. | 389 * Remove one of the directory contents filters, specified by name. |
| 336 * @param {string} name Identifier of a filter. | 390 * @param {string} name Identifier of a filter. |
| 337 */ | 391 */ |
| 338 DirectoryModel.prototype.removeFilter = function(name) { | 392 DirectoryModel.prototype.removeFilter = function(name) { |
| 339 delete this.filters_[name]; | 393 if (this.filters_[name]) |
| 394 delete this.filters_[name]; |
| 340 this.rescanSoon(); | 395 this.rescanSoon(); |
| 341 }; | 396 }; |
| 342 | 397 |
| 343 /** | 398 /** |
| 344 * Schedule rescan with short delay. | 399 * Schedule rescan with short delay. |
| 345 */ | 400 */ |
| 346 DirectoryModel.prototype.rescanSoon = function() { | 401 DirectoryModel.prototype.rescanSoon = function() { |
| 347 this.scheduleRescan(SHORT_RESCAN_INTERVAL); | 402 this.scheduleRescan(SHORT_RESCAN_INTERVAL); |
| 348 }; | 403 }; |
| 349 | 404 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 } | 474 } |
| 420 } | 475 } |
| 421 | 476 |
| 422 function onFailure() { | 477 function onFailure() { |
| 423 self.scanFailures_++; | 478 self.scanFailures_++; |
| 424 if (self.scanFailures_ <= 1) | 479 if (self.scanFailures_ <= 1) |
| 425 self.rescanLater(); | 480 self.rescanLater(); |
| 426 } | 481 } |
| 427 | 482 |
| 428 return new DirectoryModel.Scanner( | 483 return new DirectoryModel.Scanner( |
| 429 this.currentDirEntry_, | 484 this.getSearchOrCurrentDirEntry(), |
| 430 list, | 485 list, |
| 431 onSuccess, | 486 onSuccess, |
| 432 onFailure, | 487 onFailure, |
| 433 this.prefetchCacheForSorting_.bind(this), | 488 this.prefetchCacheForSorting_.bind(this), |
| 434 this.filters_); | 489 this.filters_); |
| 435 }; | 490 }; |
| 436 | 491 |
| 437 /** | 492 /** |
| 438 * @private | 493 * @private |
| 439 * @param {Array.<Entry>} entries List of files. | 494 * @param {Array.<Entry>} entries List of files. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 callback) { | 561 callback) { |
| 507 var field = this.fileList_.sortStatus.field; | 562 var field = this.fileList_.sortStatus.field; |
| 508 if (field) { | 563 if (field) { |
| 509 this.prepareSortEntries_(entries, field, callback); | 564 this.prepareSortEntries_(entries, field, callback); |
| 510 } else { | 565 } else { |
| 511 callback(); | 566 callback(); |
| 512 } | 567 } |
| 513 }; | 568 }; |
| 514 | 569 |
| 515 /** | 570 /** |
| 571 * Gets name that should be displayed in the UI for the entry. |
| 572 * @param {string} path Full path of the entry whose display name we are |
| 573 * getting. |
| 574 * @param {string} defaultName Default name to use if no name is calculated. |
| 575 * @return {string} Name to be used for display. |
| 576 */ |
| 577 DirectoryModel.prototype.getDisplayName = function(path, defaultName) { |
| 578 var searchResultName = util.getFileAndDisplayNameForGDataSearchResult(path); |
| 579 return searchResultName ? searchResultName.displayName : defaultName; |
| 580 }; |
| 581 |
| 582 /** |
| 583 * Creates file name that should be used as a new file name in filesystem |
| 584 * operations while renaming. If the given entry is not a gdata search result |
| 585 * entry, |displayName| will be used. |
| 586 * |
| 587 * @private |
| 588 * @param {Entry} entry Entry which is being renamed. |
| 589 * @param {string} displayName The new file name provided by user. |
| 590 * @return {string} File name that should be used in renaming filesystem |
| 591 * operations. |
| 592 */ |
| 593 DirectoryModel.prototype.getEntryNameForRename_ = function(entry, displayName) { |
| 594 // If we are renaming gdata search result, we'll have to format newName to |
| 595 // use in file system operation like: <resource_id>.<file_name>. |
| 596 var searchResultName = |
| 597 util.getFileAndDisplayNameForGDataSearchResult(entry.fullPath); |
| 598 return searchResultName ? searchResultName.resourceId + '.' + displayName : |
| 599 displayName; |
| 600 }; |
| 601 |
| 602 /** |
| 516 * Delete the list of files and directories from filesystem and | 603 * Delete the list of files and directories from filesystem and |
| 517 * update the file list. | 604 * update the file list. |
| 518 * @param {Array.<Entry>} entries Entries to delete. | 605 * @param {Array.<Entry>} entries Entries to delete. |
| 519 * @param {function()=} opt_callback Called when finished. | 606 * @param {function()=} opt_callback Called when finished. |
| 520 */ | 607 */ |
| 521 DirectoryModel.prototype.deleteEntries = function(entries, opt_callback) { | 608 DirectoryModel.prototype.deleteEntries = function(entries, opt_callback) { |
| 522 var downcount = entries.length + 1; | 609 var downcount = entries.length + 1; |
| 523 | 610 |
| 524 var onComplete = opt_callback ? function() { | 611 var onComplete = opt_callback ? function() { |
| 525 if (--downcount == 0) | 612 if (--downcount == 0) |
| (...skipping 16 matching lines...) Expand all Loading... |
| 542 onSuccess, | 629 onSuccess, |
| 543 util.flog('Error deleting ' + entry.fullPath, onComplete)); | 630 util.flog('Error deleting ' + entry.fullPath, onComplete)); |
| 544 } | 631 } |
| 545 onComplete(); | 632 onComplete(); |
| 546 }; | 633 }; |
| 547 | 634 |
| 548 /** | 635 /** |
| 549 * @param {string} name Filename. | 636 * @param {string} name Filename. |
| 550 */ | 637 */ |
| 551 DirectoryModel.prototype.onEntryChanged = function(name) { | 638 DirectoryModel.prototype.onEntryChanged = function(name) { |
| 552 var currentEntry = this.currentDirEntry_; | 639 var currentEntry = this.getSearchOrCurrentDirEntry(); |
| 640 if (currentEntry != this.currentDirEntry_) |
| 641 return; |
| 553 var dm = this.fileList_; | 642 var dm = this.fileList_; |
| 554 var self = this; | 643 var self = this; |
| 555 | 644 |
| 556 function onEntryFound(entry) { | 645 function onEntryFound(entry) { |
| 646 // Do nothing if current directory changed during async operations. |
| 647 if (self.getSearchOrCurrentDirEntry() != currentEntry) |
| 648 return; |
| 557 self.prefetchCacheForSorting_([entry], function() { | 649 self.prefetchCacheForSorting_([entry], function() { |
| 558 // Do nothing if current directory changed during async operations. | 650 // Do nothing if current directory changed during async operations. |
| 559 if (self.currentDirEntry_ != currentEntry) | 651 if (self.getSearchOrCurrentDirEntry() != currentEntry) |
| 560 return; | 652 return; |
| 561 | 653 |
| 562 var index = self.findIndexByName_(name); | 654 var index = self.findIndexByName_(name); |
| 563 if (index >= 0) | 655 if (index >= 0) |
| 564 dm.splice(index, 1, entry); | 656 dm.splice(index, 1, entry); |
| 565 else | 657 else |
| 566 dm.splice(dm.length, 0, entry); | 658 dm.splice(dm.length, 0, entry); |
| 567 }); | 659 }); |
| 568 }; | 660 }; |
| 569 | 661 |
| 570 function onError(err) { | 662 function onError(err) { |
| 571 // Do nothing if current directory changed during async operations. | 663 // Do nothing if current directory changed during async operations. |
| 572 if (self.currentDirEntry_ != currentEntry) | 664 if (self.currentDirEntry_ != currentEntry) |
| 573 return; | 665 return; |
| 574 if (err.code != FileError.NOT_FOUND_ERR) { | 666 if (err.code != FileError.NOT_FOUND_ERR) { |
| 575 self.rescanLater(); | 667 self.rescanLater(); |
| 576 return; | 668 return; |
| 577 } | 669 } |
| 578 | 670 |
| 579 var index = self.findIndexByName_(name); | 671 var index = self.findIndexByName_(name); |
| 580 if (index >= 0) | 672 if (index >= 0) |
| 581 dm.splice(index, 1); | 673 dm.splice(index, 1); |
| 582 }; | 674 }; |
| 583 | 675 |
| 584 util.resolvePath(this.currentDirEntry_, name, onEntryFound, onError); | 676 util.resolvePath(currentEntry, name, onEntryFound, onError); |
| 585 }; | 677 }; |
| 586 | 678 |
| 587 /** | 679 /** |
| 588 * @private | 680 * @private |
| 589 * @param {string} name Filename. | 681 * @param {string} name Filename. |
| 590 * @return {number} The index in the fileList. | 682 * @return {number} The index in the fileList. |
| 591 */ | 683 */ |
| 592 DirectoryModel.prototype.findIndexByName_ = function(name) { | 684 DirectoryModel.prototype.findIndexByName_ = function(name) { |
| 593 var dm = this.fileList_; | 685 var dm = this.fileList_; |
| 594 for (var i = 0; i < dm.length; i++) | 686 for (var i = 0; i < dm.length; i++) |
| 595 if (dm.item(i).name == name) | 687 if (dm.item(i).name == name) |
| 596 return i; | 688 return i; |
| 597 return -1; | 689 return -1; |
| 598 }; | 690 }; |
| 599 | 691 |
| 600 /** | 692 /** |
| 601 * Rename the entry in the filesystem and update the file list. | 693 * Rename the entry in the filesystem and update the file list. |
| 602 * @param {Entry} entry Entry to rename. | 694 * @param {Entry} entry Entry to rename. |
| 603 * @param {string} newName New name. | 695 * @param {string} newDisplayName New name. |
| 604 * @param {function} errorCallback Called on error. | 696 * @param {function} errorCallback Called on error. |
| 605 * @param {function} opt_successCallback Called on success. | 697 * @param {function} opt_successCallback Called on success. |
| 606 */ | 698 */ |
| 607 DirectoryModel.prototype.renameEntry = function(entry, newName, errorCallback, | 699 DirectoryModel.prototype.renameEntry = function(entry, newDisplayName, |
| 700 errorCallback, |
| 608 opt_successCallback) { | 701 opt_successCallback) { |
| 609 var self = this; | 702 var self = this; |
| 610 function onSuccess(newEntry) { | 703 function onSuccess(newEntry) { |
| 611 self.prefetchCacheForSorting_([newEntry], function() { | 704 self.prefetchCacheForSorting_([newEntry], function() { |
| 612 var fileList = self.fileList_; | 705 var fileList = self.fileList_; |
| 613 var index = fileList.indexOf(entry); | 706 var index = fileList.indexOf(entry); |
| 614 if (index >= 0) | 707 if (index >= 0) |
| 615 fileList.splice(index, 1, newEntry); | 708 fileList.splice(index, 1, newEntry); |
| 616 self.selectEntry(newName); | 709 self.selectEntry(newEntry.name); |
| 617 // If the entry doesn't exist in the list it mean that it updated from | 710 // If the entry doesn't exist in the list it mean that it updated from |
| 618 // outside (probably by directory rescan). | 711 // outside (probably by directory rescan). |
| 619 if (opt_successCallback) | 712 if (opt_successCallback) |
| 620 opt_successCallback(); | 713 opt_successCallback(); |
| 621 }); | 714 }); |
| 622 } | 715 } |
| 623 entry.moveTo(this.currentDirEntry_, newName, onSuccess, errorCallback); | 716 |
| 717 var newEntryName = this.getEntryNameForRename_(entry, newDisplayName); |
| 718 entry.moveTo(this.getSearchOrCurrentDirEntry(), newEntryName, onSuccess, |
| 719 errorCallback); |
| 624 }; | 720 }; |
| 625 | 721 |
| 626 /** | 722 /** |
| 627 * Checks if current directory contains a file or directory with this name. | 723 * Checks if current directory contains a file or directory with this name. |
| 628 * @param {string} newName Name to check. | 724 * @param {string} entry Entry to which newName will be given. |
| 725 * @param {string} displayName Name to check. |
| 629 * @param {function(boolean, boolean?)} callback Called when the result's | 726 * @param {function(boolean, boolean?)} callback Called when the result's |
| 630 * available. First parameter is true if the entry exists and second | 727 * available. First parameter is true if the entry exists and second |
| 631 * is true if it's a file. | 728 * is true if it's a file. |
| 632 */ | 729 */ |
| 633 DirectoryModel.prototype.doesExist = function(newName, callback) { | 730 DirectoryModel.prototype.doesExist = function(entry, displayName, callback) { |
| 634 util.resolvePath(this.currentDirEntry_, newName, | 731 var entryName = this.getEntryNameForRename_(entry, displayName); |
| 732 |
| 733 util.resolvePath(this.getSearchOrCurrentDirEntry(), entryName, |
| 635 function(entry) { | 734 function(entry) { |
| 636 callback(true, entry.isFile); | 735 callback(true, entry.isFile); |
| 637 }, | 736 }, |
| 638 callback.bind(window, false)); | 737 callback.bind(window, false)); |
| 639 }; | 738 }; |
| 640 | 739 |
| 641 /** | 740 /** |
| 642 * Creates directory and updates the file list. | 741 * Creates directory and updates the file list. |
| 643 * | 742 * |
| 644 * @param {string} name Directory name. | 743 * @param {string} name Directory name. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 670 this.currentDirEntry_.getDirectory(name, {create: true, exclusive: true}, | 769 this.currentDirEntry_.getDirectory(name, {create: true, exclusive: true}, |
| 671 onSuccess, errorCallback); | 770 onSuccess, errorCallback); |
| 672 }; | 771 }; |
| 673 | 772 |
| 674 /** | 773 /** |
| 675 * Changes directory. Causes 'directory-change' event. | 774 * Changes directory. Causes 'directory-change' event. |
| 676 * | 775 * |
| 677 * @param {string} path New current directory path. | 776 * @param {string} path New current directory path. |
| 678 */ | 777 */ |
| 679 DirectoryModel.prototype.changeDirectory = function(path) { | 778 DirectoryModel.prototype.changeDirectory = function(path) { |
| 680 this.resolveDirectory(path, function(directoryEntry) { | 779 var targetPath = path; |
| 780 // We should not be changing directory to gdata search path. If we do, default |
| 781 // to gdata root. |
| 782 if (DirectoryModel.isGDataSearchPath(path)) { |
| 783 console.error('Attempt to change directory to search path.'); |
| 784 targetPath = '/' + DirectoryModel.GDATA_DIRECTORY; |
| 785 } |
| 786 |
| 787 this.resolveDirectory(targetPath, function(directoryEntry) { |
| 681 this.changeDirectoryEntry_(false, directoryEntry); | 788 this.changeDirectoryEntry_(false, directoryEntry); |
| 682 }.bind(this), function(error) { | 789 }.bind(this), function(error) { |
| 683 console.error('Error changing directory to ' + path + ': ', error); | 790 console.error('Error changing directory to ' + path + ': ', error); |
| 684 }); | 791 }); |
| 685 }; | 792 }; |
| 686 | 793 |
| 687 /** | 794 /** |
| 688 * Resolves absolute directory path. Handles GData stub. | 795 * Resolves absolute directory path. Handles GData stub. |
| 689 * @param {string} path Path to the directory. | 796 * @param {string} path Path to the directory. |
| 690 * @param {function(DirectoryEntry} successCallback Success callback. | 797 * @param {function(DirectoryEntry} successCallback Success callback. |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 752 * changed. | 859 * changed. |
| 753 * | 860 * |
| 754 * @private | 861 * @private |
| 755 * @param {boolean} initial True if it comes from setupPath and | 862 * @param {boolean} initial True if it comes from setupPath and |
| 756 * false if caused by an user action. | 863 * false if caused by an user action. |
| 757 * @param {DirectoryEntry} dirEntry The absolute path to the new directory. | 864 * @param {DirectoryEntry} dirEntry The absolute path to the new directory. |
| 758 * @param {function} opt_callback Executed if the directory loads successfully. | 865 * @param {function} opt_callback Executed if the directory loads successfully. |
| 759 */ | 866 */ |
| 760 DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry, | 867 DirectoryModel.prototype.changeDirectoryEntry_ = function(initial, dirEntry, |
| 761 opt_callback) { | 868 opt_callback) { |
| 869 this.clearSearch_(); |
| 762 var previous = this.currentDirEntry_; | 870 var previous = this.currentDirEntry_; |
| 763 this.currentDirEntry_ = dirEntry; | 871 this.currentDirEntry_ = dirEntry; |
| 764 function onRescanComplete() { | 872 function onRescanComplete() { |
| 765 if (opt_callback) | 873 if (opt_callback) |
| 766 opt_callback(); | 874 opt_callback(); |
| 767 // For tests that open the dialog to empty directories, everything | 875 // For tests that open the dialog to empty directories, everything |
| 768 // is loaded at this point. | 876 // is loaded at this point. |
| 769 chrome.test.sendMessage('directory-change-complete'); | 877 chrome.test.sendMessage('directory-change-complete'); |
| 770 } | 878 } |
| 771 this.updateRootsListSelection_(); | 879 this.updateRootsListSelection_(); |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1128 /** | 1236 /** |
| 1129 * @param {string} path Path | 1237 * @param {string} path Path |
| 1130 * @return {boolean} If current directory is system. | 1238 * @return {boolean} If current directory is system. |
| 1131 */ | 1239 */ |
| 1132 DirectoryModel.isSystemDirectory = function(path) { | 1240 DirectoryModel.isSystemDirectory = function(path) { |
| 1133 return path == '/' + DirectoryModel.REMOVABLE_DIRECTORY || | 1241 return path == '/' + DirectoryModel.REMOVABLE_DIRECTORY || |
| 1134 path == '/' + DirectoryModel.ARCHIVE_DIRECTORY; | 1242 path == '/' + DirectoryModel.ARCHIVE_DIRECTORY; |
| 1135 }; | 1243 }; |
| 1136 | 1244 |
| 1137 /** | 1245 /** |
| 1246 * Performs search and displays results. The search type is dependent on the |
| 1247 * current directory. If we are currently on gdata, server side content search |
| 1248 * over gdata mount point. If the current directory is not on the gdata, file |
| 1249 * name search over current directory wil be performed. |
| 1250 * |
| 1251 * @param {string} query Query that will be searched for. |
| 1252 * @param {function} onSearchRescan Function that will be called when the search |
| 1253 * directory is rescanned (i.e. search results are displayed) |
| 1254 * @param {function} onClearSearch Function to be called when search state gets |
| 1255 * cleared. |
| 1256 */ |
| 1257 DirectoryModel.prototype.search = function(query, |
| 1258 onSearchRescan, |
| 1259 onClearSearch) { |
| 1260 if (!query) { |
| 1261 if (this.isSearching_) |
| 1262 this.clearSearch_(); |
| 1263 return; |
| 1264 } |
| 1265 |
| 1266 this.isSearching_ = true; |
| 1267 |
| 1268 // If we alreaqdy have event listener for an old search, we have to remove it. |
| 1269 if (this.onSearchRescan_) |
| 1270 this.removeEventListener('rescan-completed', this.onSearchRescan_); |
| 1271 |
| 1272 this.onSearchRescan_ = onSearchRescan; |
| 1273 this.onClearSearch_ = onClearSearch; |
| 1274 |
| 1275 this.addEventListener('rescan-completed', this.onSearchRescan_); |
| 1276 |
| 1277 // If we are offline, let's fallback to file name search inside dir. |
| 1278 if (this.getRootType() == DirectoryModel.RootType.GDATA && |
| 1279 !this.isOffline()) { |
| 1280 var self = this; |
| 1281 // Create shadow directory which will contain search results. |
| 1282 this.root_.getDirectory(DirectoryModel.createGDataSearchPath(query), |
| 1283 {create: false}, |
| 1284 function(dir) { |
| 1285 self.searchDirEntry_ = dir; |
| 1286 self.rescanSoon(); |
| 1287 }, |
| 1288 function() { |
| 1289 self.isSearching_ = false; |
| 1290 }); |
| 1291 } else { |
| 1292 var queryLC = query.toLowerCase(); |
| 1293 this.searchDirEntry_ = this.currentDirEntry_; |
| 1294 this.addFilter( |
| 1295 'searchbox', |
| 1296 function(e) { |
| 1297 return e.name.toLowerCase().indexOf(queryLC) > -1; |
| 1298 }); |
| 1299 } |
| 1300 }; |
| 1301 |
| 1302 |
| 1303 /** |
| 1304 * Clears any state set by previous searches. |
| 1305 * @private |
| 1306 */ |
| 1307 DirectoryModel.prototype.clearSearch_ = function() { |
| 1308 if (!this.isSearching_) |
| 1309 return; |
| 1310 this.searchDirEntry_ = null; |
| 1311 this.isSearching_ = false; |
| 1312 // This will trigger rescan. |
| 1313 this.removeFilter('searchbox'); |
| 1314 |
| 1315 if (this.onSearchRescan_) { |
| 1316 this.removeEventListener('rescan-completed', this.onSearchRescan_); |
| 1317 this.onSearchRescan_ = null; |
| 1318 } |
| 1319 |
| 1320 if (this.onClearSearch_) { |
| 1321 this.onClearSearch_(); |
| 1322 this.onClearSearch_ = null; |
| 1323 } |
| 1324 }; |
| 1325 |
| 1326 /** |
| 1138 * @param {string} path Any path. | 1327 * @param {string} path Any path. |
| 1139 * @return {string} The root path. | 1328 * @return {string} The root path. |
| 1140 */ | 1329 */ |
| 1141 DirectoryModel.getRootPath = function(path) { | 1330 DirectoryModel.getRootPath = function(path) { |
| 1142 var type = DirectoryModel.getRootType(path); | 1331 var type = DirectoryModel.getRootType(path); |
| 1143 | 1332 |
| 1144 if (type == DirectoryModel.RootType.DOWNLOADS) | 1333 if (type == DirectoryModel.RootType.DOWNLOADS) |
| 1145 return '/' + DirectoryModel.DOWNLOADS_DIRECTORY; | 1334 return '/' + DirectoryModel.DOWNLOADS_DIRECTORY; |
| 1146 if (type == DirectoryModel.RootType.GDATA) | 1335 if (type == DirectoryModel.RootType.GDATA) |
| 1147 return '/' + DirectoryModel.GDATA_DIRECTORY; | 1336 return '/' + DirectoryModel.GDATA_DIRECTORY; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1192 * @param {string} path A path. | 1381 * @param {string} path A path. |
| 1193 * @return {boolean} True if it is a path to the root. | 1382 * @return {boolean} True if it is a path to the root. |
| 1194 */ | 1383 */ |
| 1195 DirectoryModel.isRootPath = function(path) { | 1384 DirectoryModel.isRootPath = function(path) { |
| 1196 if (path[path.length - 1] == '/') | 1385 if (path[path.length - 1] == '/') |
| 1197 path = path.substring(0, path.length - 1); | 1386 path = path.substring(0, path.length - 1); |
| 1198 return DirectoryModel.getRootPath(path) == path; | 1387 return DirectoryModel.getRootPath(path) == path; |
| 1199 }; | 1388 }; |
| 1200 | 1389 |
| 1201 /** | 1390 /** |
| 1391 * Checks if the provided path is under gdata search. |
| 1392 * |
| 1393 * @param {string} path Path to be tested. |
| 1394 * @return {boolean} Is the path gdata search path. |
| 1395 */ |
| 1396 DirectoryModel.isGDataSearchPath = function(path) { |
| 1397 return path == DirectoryModel.GDATA_SEARCH_ROOT_PATH || |
| 1398 path.indexOf(DirectoryModel.GDATA_SEARCH_ROOT_PATH + '/') == 0; |
| 1399 }; |
| 1400 |
| 1401 /** |
| 1402 * Creates directory path in which gdata content search results for |query| |
| 1403 * should be displayed. |
| 1404 * |
| 1405 * @param {string} query Search query. |
| 1406 * @return {string} Virtual directory path for search results. |
| 1407 */ |
| 1408 DirectoryModel.createGDataSearchPath = function(query) { |
| 1409 return DirectoryModel.GDATA_SEARCH_ROOT_PATH + '/' + query; |
| 1410 }; |
| 1411 |
| 1412 /** |
| 1202 * @constructor | 1413 * @constructor |
| 1203 * @extends cr.EventTarget | 1414 * @extends cr.EventTarget |
| 1204 * @param {DirectoryEntry} dir Directory to scan. | 1415 * @param {DirectoryEntry} dir Directory to scan. |
| 1205 * @param {Array.<Entry>|cr.ui.ArrayDataModel} list Target to put the files. | 1416 * @param {Array.<Entry>|cr.ui.ArrayDataModel} list Target to put the files. |
| 1206 * @param {function} successCallback Callback to call when (and if) scan | 1417 * @param {function} successCallback Callback to call when (and if) scan |
| 1207 * successfully completed. | 1418 * successfully completed. |
| 1208 * @param {function} errorCallback Callback to call in case of IO error. | 1419 * @param {function} errorCallback Callback to call in case of IO error. |
| 1209 * @param {function(Array.<Entry>):void, Function)} preprocessChunk | 1420 * @param {function(Array.<Entry>):void, Function)} preprocessChunk |
| 1210 * Callback to preprocess each chunk of files. | 1421 * Callback to preprocess each chunk of files. |
| 1211 * @param {Object.<string, function(Entry):Boolean>} filters The map of filters | 1422 * @param {Object.<string, function(Entry):Boolean>} filters The map of filters |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1288 /** | 1499 /** |
| 1289 * @private | 1500 * @private |
| 1290 */ | 1501 */ |
| 1291 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { | 1502 DirectoryModel.Scanner.prototype.recordMetrics_ = function() { |
| 1292 metrics.recordInterval('DirectoryScan'); | 1503 metrics.recordInterval('DirectoryScan'); |
| 1293 if (this.dir_.fullPath == | 1504 if (this.dir_.fullPath == |
| 1294 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { | 1505 '/' + DirectoryModel.DOWNLOADS_DIRECTORY) { |
| 1295 metrics.recordMediumCount('DownloadsCount', this.list_.length); | 1506 metrics.recordMediumCount('DownloadsCount', this.list_.length); |
| 1296 } | 1507 } |
| 1297 }; | 1508 }; |
| OLD | NEW |