Move action_runner.py out of actions folder prior to moving actions to internal.
[chromium-blink-merge.git] / ui / file_manager / gallery / js / entry_list_watcher.js
blobe4e1149d87ea01f0b4e14bf5cfb5a72445dc2445
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.<string, 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   // Mark all existing watchers as candidates to be removed.
53   var diff = {};
54   for (var url in this.watchers_) {
55     diff[url] = -1;
56   }
58   // Obtains the set of new watcher.
59   this.watchers_ = {};
60   for (var i = 0; i < this.list_.length; i++) {
61     var entry = this.getEntry(this.list_.item(i));
62     var parentURL = entry.toURL().replace(/[^\/]+\/?$/, '');
63     this.watchers_[parentURL] = true;
64   }
66   // Mark new watchers to be added, and existing watchers to be kept.
67   for (var url in this.watchers_) {
68     diff[url] = (diff[url] || 0) + 1;
69   }
71   // Check the number in diff.
72   // -1: watcher exists in the old set, but does not exists in the new set.
73   // 0: watcher exists in both sets.
74   // 1: watcher does not exists in the old set, but exists in the new set.
75   var reportError = function() {
76     if (chrome.runtime.lastError)
77       console.error(chrome.runtime.lastError);
78   };
79   for (var url in diff) {
80     switch (diff[url]) {
81       case 1:
82         chrome.fileManagerPrivate.addFileWatch(url, reportError);
83         break;
84       case -1:
85         chrome.fileManagerPrivate.removeFileWatch(url, reportError);
86         break;
87       case 0:
88         break;
89       default:
90         assertNotReached();
91         break;
92     }
93   }
96 /**
97  * @param {!FileWatchEvent} event
98  * @private
99  */
100 EntryListWatcher.prototype.onDirectoryChanged_ = function(event) {
101   // Add '/' to the tail for checking if the each entry's URL is child URL of
102   // the URL or not by using entryURL.indexOf(thisUrl) === 0.
103   var url = event.entry.toURL().replace(/\/?$/, '/');
104   var promiseList = [];
105   var removedEntryURL = {};
106   for (var i = 0; i < this.list_.length; i++) {
107     var entry = this.getEntry(this.list_.item(i));
108     // Remove trailing '/' to prevent calling getMetadata in the case where the
109     // event.entry and the entry are same.
110     var entryURL = entry.toURL().replace(/\/$/, '');
111     if (entry.toURL().indexOf(url) !== 0)
112       continue;
113     // Look for non-existing files by using getMetadata.
114     // getMetadata returns NOT_FOUND error for non-existing files.
115     promiseList.push(new Promise(entry.getMetadata.bind(entry)).catch(
116         function(url) {
117           removedEntryURL[url] = true;
118         }.bind(null, entry.toURL())));
119   }
120   Promise.all(promiseList).then(function() {
121     var i = 0;
122     while (i < this.list_.length) {
123       var url = this.getEntry(this.list_.item(i)).toURL();
124       if (removedEntryURL[url]) {
125         this.list_.splice(i, 1);
126       } else {
127         i++;
128       }
129     }
130   }.bind(this));