Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / file_manager / gallery / js / entry_list_watcher.js
blob453a29d6cae7513792efa1f486c39fc1eae1d088
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6  * Watcher for entry lists.
7  * It watches entries and remove the item if the entry is removed from file
8  * system.
9  * @param {!cr.ui.ArrayDataModel} list
10  * @constructor
11  * @struct
12  */
13 function EntryListWatcher(list) {
14   /**
15    * Watched list.
16    * @type {!cr.ui.ArrayDataModel}
17    * @const
18    * @private
19    */
20   this.list_ = list;
22   /**
23    * Set of watched URL.
24    * Key is watched entry URL. Value is always true.
25    * @type {!Object<boolean>}
26    * @private
27    */
28   this.watchers_ = {};
30   this.list_.addEventListener('splice', this.onSplice_.bind(this));
31   chrome.fileManagerPrivate.onDirectoryChanged.addListener(
32       this.onDirectoryChanged_.bind(this));
34   this.onSplice_(null);
37 /**
38  * Obtains entry from ArrayDataModel's item.
39  * @param {*} item Item in ArrayDataModel.
40  * @protected
41  * @return {!FileEntry}
42  */
43 EntryListWatcher.prototype.getEntry = function(item) {
44   return /** @type {!FileEntry} */ (item);
47 /**
48  * @param {Event} event
49  * @private
50  */
51 EntryListWatcher.prototype.onSplice_ = function(event) {
52   // TODO(mtomasz, hirono): Remove operations on URLs as they won't work after
53   // switching to isolated entries.
55   // Mark all existing watchers as candidates to be removed.
56   var diff = {};
57   for (var url in this.watchers_) {
58     diff[url] = -1;
59   }
61   // Obtains the set of new watcher.
62   this.watchers_ = {};
63   for (var i = 0; i < this.list_.length; i++) {
64     var entry = this.getEntry(this.list_.item(i));
65     var parentURL = entry.toURL().replace(/[^\/]+\/?$/, '');
66     this.watchers_[parentURL] = true;
67   }
69   // Mark new watchers to be added, and existing watchers to be kept.
70   for (var url in this.watchers_) {
71     diff[url] = (diff[url] || 0) + 1;
72   }
74   // Check the number in diff.
75   // -1: watcher exists in the old set, but does not exists in the new set.
76   // 0: watcher exists in both sets.
77   // 1: watcher does not exists in the old set, but exists in the new set.
78   var reportError = function() {
79     if (chrome.runtime.lastError)
80       console.error(chrome.runtime.lastError.name);
81   };
82   for (var url in diff) {
83     switch (diff[url]) {
84       case 1:
85         window.webkitResolveLocalFileSystemURL(url, function(entry) {
86           reportError();
87           chrome.fileManagerPrivate.addFileWatch(entry, reportError);
88         });
89         break;
90       case -1:
91         window.webkitResolveLocalFileSystemURL(url, function(entry) {
92           reportError();
93           chrome.fileManagerPrivate.removeFileWatch(entry, reportError);
94         });
95         break;
96       case 0:
97         break;
98       default:
99         assertNotReached();
100         break;
101     }
102   }
106  * @param {!FileWatchEvent} event
107  * @private
108  */
109 EntryListWatcher.prototype.onDirectoryChanged_ = function(event) {
110   // Add '/' to the tail for checking if the each entry's URL is child URL of
111   // the URL or not by using entryURL.indexOf(thisUrl) === 0.
112   var url = event.entry.toURL().replace(/\/?$/, '/');
113   var promiseList = [];
114   var removedEntryURL = {};
115   for (var i = 0; i < this.list_.length; i++) {
116     var entry = this.getEntry(this.list_.item(i));
117     // Remove trailing '/' to prevent calling getMetadata in the case where the
118     // event.entry and the entry are same.
119     var entryURL = entry.toURL().replace(/\/$/, '');
120     if (entry.toURL().indexOf(url) !== 0)
121       continue;
122     // Look for non-existing files by using getMetadata.
123     // getMetadata returns NOT_FOUND error for non-existing files.
124     promiseList.push(new Promise(entry.getMetadata.bind(entry)).catch(
125         function(url) {
126           removedEntryURL[url] = true;
127         }.bind(null, entry.toURL())));
128   }
129   Promise.all(promiseList).then(function() {
130     var i = 0;
131     while (i < this.list_.length) {
132       var url = this.getEntry(this.list_.item(i)).toURL();
133       if (removedEntryURL[url]) {
134         this.list_.splice(i, 1);
135       } else {
136         i++;
137       }
138     }
139   }.bind(this));