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

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

Issue 39123003: [Files.app] Split the JavaScript files into subdirectories: common, background, and foreground (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed test failure. Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 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.
4
5 /**
6 * Model for the folder shortcuts. This object is cr.ui.ArrayDataModel-like
7 * object with additional methods for the folder shortcut feature.
8 * This uses chrome.storage as backend. Items are always sorted by file path.
9 *
10 * @constructor
11 * @extends {cr.EventTarget}
12 */
13 function FolderShortcutsDataModel() {
14 this.array_ = [];
15
16 /**
17 * Eliminate unsupported folders from the list.
18 *
19 * @param {Array.<string>} array Folder array which may contain the
20 * unsupported folders.
21 * @return {Array.<string>} Folder list without unsupported folder.
22 */
23 var filter = function(array) {
24 return array.filter(PathUtil.isEligibleForFolderShortcut);
25 };
26
27 // Loads the contents from the storage to initialize the array.
28 chrome.storage.sync.get(FolderShortcutsDataModel.NAME, function(value) {
29 if (!(FolderShortcutsDataModel.NAME in value))
30 return;
31
32 // Since the value comes from outer resource, we have to check it just in
33 // case.
34 var list = value[FolderShortcutsDataModel.NAME];
35 if (list instanceof Array) {
36 list = filter(list);
37
38 // Record metrics.
39 metrics.recordSmallCount('FolderShortcut.Count', list.length);
40
41 var permutation = this.calculatePermutation_(this.array_, list);
42 this.array_ = list;
43 this.firePermutedEvent_(permutation);
44 }
45 }.bind(this));
46
47 // Listening for changes in the storage.
48 chrome.storage.onChanged.addListener(function(changes, namespace) {
49 if (!(FolderShortcutsDataModel.NAME in changes) || namespace != 'sync')
50 return;
51
52 var list = changes[FolderShortcutsDataModel.NAME].newValue;
53 // Since the value comes from outer resource, we have to check it just in
54 // case.
55 if (list instanceof Array) {
56 list = filter(list);
57
58 // If the list is not changed, do nothing and just return.
59 if (this.array_.length == list.length) {
60 var changed = false;
61 for (var i = 0; i < this.array_.length; i++) {
62 // Same item check: must be exact match.
63 if (this.array_[i] != list[i]) {
64 changed = true;
65 break;
66 }
67 }
68 if (!changed)
69 return;
70 }
71
72 var permutation = this.calculatePermutation_(this.array_, list);
73 this.array_ = list;
74 this.firePermutedEvent_(permutation);
75 }
76 }.bind(this));
77 }
78
79 /**
80 * Key name in chrome.storage. The array are stored with this name.
81 * @type {string}
82 * @const
83 */
84 FolderShortcutsDataModel.NAME = 'folder-shortcuts-list';
85
86 FolderShortcutsDataModel.prototype = {
87 __proto__: cr.EventTarget.prototype,
88
89 /**
90 * @return {number} Number of elements in the array.
91 */
92 get length() {
93 return this.array_.length;
94 },
95
96 /**
97 * Returns the paths in the given range as a new array instance. The
98 * arguments and return value are compatible with Array.slice().
99 *
100 * @param {number} start Where to start the selection.
101 * @param {number=} opt_end Where to end the selection.
102 * @return {Array.<string>} Paths in the selected range.
103 */
104 slice: function(begin, opt_end) {
105 return this.array_.slice(begin, opt_end);
106 },
107
108 /**
109 * @param {number} index Index of the element to be retrieved.
110 * @return {string} The value of the |index|-th element.
111 */
112 item: function(index) {
113 return this.array_[index];
114 },
115
116 /**
117 * @param {string} value Value of the element to be retrieved.
118 * @return {number} Index of the element with the specified |value|.
119 */
120 getIndex: function(value) {
121 for (var i = 0; i < this.length; i++) {
122 // Same item check: must be exact match.
123 if (this.array_[i] == value) {
124 return i;
125 }
126 }
127 return -1;
128 },
129
130 /**
131 * Compares 2 strings and returns a number indicating one string comes before
132 * or after or is the same as the other string in sort order.
133 *
134 * @param {string} a String1.
135 * @param {string} b String2.
136 * @return {boolean} Return -1, if String1 < String2. Return 0, if String1 ==
137 * String2. Otherwise, return 1.
138 */
139 compare: function(a, b) {
140 return a.localeCompare(b,
141 undefined, // locale parameter, use default locale.
142 {usage: 'sort', numeric: true});
143 },
144
145 /**
146 * Adds the given item to the array. If there were already same item in the
147 * list, return the index of the existing item without adding a duplicate
148 * item.
149 *
150 * @param {string} value Value to be added into the array.
151 * @return {number} Index in the list which the element added to.
152 */
153 add: function(value) {
154 var oldArray = this.array_.slice(0); // Shallow copy.
155 var addedIndex = -1;
156 for (var i = 0; i < this.length; i++) {
157 // Same item check: must be exact match.
158 if (this.array_[i] == value)
159 return i;
160
161 // Since the array is sorted, new item will be added just before the first
162 // larger item.
163 if (this.compare(this.array_[i], value) >= 0) {
164 this.array_.splice(i, 0, value);
165 addedIndex = i;
166 break;
167 }
168 }
169 // If value is not added yet, add it at the last.
170 if (addedIndex == -1) {
171 this.array_.push(value);
172 addedIndex = this.length;
173 }
174
175 this.firePermutedEvent_(
176 this.calculatePermutation_(oldArray, this.array_));
177 this.save_();
178 metrics.recordUserAction('FolderShortcut.Add');
179 return addedIndex;
180 },
181
182 /**
183 * Removes the given item from the array.
184 * @param {string} value Value to be removed from the array.
185 * @return {number} Index in the list which the element removed from.
186 */
187 remove: function(value) {
188 var removedIndex = -1;
189 var oldArray = this.array_.slice(0); // Shallow copy.
190 for (var i = 0; i < this.length; i++) {
191 // Same item check: must be exact match.
192 if (this.array_[i] == value) {
193 this.array_.splice(i, 1);
194 removedIndex = i;
195 break;
196 }
197 }
198
199 if (removedIndex != -1) {
200 this.firePermutedEvent_(
201 this.calculatePermutation_(oldArray, this.array_));
202 this.save_();
203 metrics.recordUserAction('FolderShortcut.Remove');
204 return removedIndex;
205 }
206
207 // No item is removed.
208 return -1;
209 },
210
211 /**
212 * @param {string} path Path to be checked.
213 * @return {boolean} True if the given |path| exists in the array. False
214 * otherwise.
215 */
216 exists: function(path) {
217 var index = this.getIndex(path);
218 return (index >= 0);
219 },
220
221 /**
222 * Saves the current array to chrome.storage.
223 * @private
224 */
225 save_: function() {
226 var obj = {};
227 obj[FolderShortcutsDataModel.NAME] = this.array_;
228 chrome.storage.sync.set(obj, function() {});
229 },
230
231 /**
232 * Creates a permutation array for 'permuted' event, which is compatible with
233 * a permutation array used in cr/ui/array_data_model.js.
234 *
235 * @param {array} oldArray Previous array before changing.
236 * @param {array} newArray New array after changing.
237 * @return {Array.<number>} Created permutation array.
238 * @private
239 */
240 calculatePermutation_: function(oldArray, newArray) {
241 var oldIndex = 0; // Index of oldArray.
242 var newIndex = 0; // Index of newArray.
243
244 // Note that both new and old arrays are sorted.
245 var permutation = [];
246 for (; oldIndex < oldArray.length; oldIndex++) {
247 if (newIndex >= newArray.length) {
248 // oldArray[oldIndex] is deleted, which is not in the new array.
249 permutation[oldIndex] = -1;
250 continue;
251 }
252
253 while (newIndex < newArray.length) {
254 // Unchanged item, which exists in both new and old array. But the
255 // index may be changed.
256 if (oldArray[oldIndex] == newArray[newIndex]) {
257 permutation[oldIndex] = newIndex;
258 newIndex++;
259 break;
260 }
261
262 // oldArray[oldIndex] is deleted, which is not in the new array.
263 if (this.compare(oldArray[oldIndex], newArray[newIndex]) < 0) {
264 permutation[oldIndex] = -1;
265 break;
266 }
267
268 // In the case of this.compare(oldArray[oldIndex]) > 0:
269 // newArray[newIndex] is added, which is not in the old array.
270 newIndex++;
271 }
272 }
273 return permutation;
274 },
275
276 /**
277 * Fires a 'permuted' event, which is compatible with cr.ui.ArrayDataModel.
278 * @param {Array.<number>} Permutation array.
279 */
280 firePermutedEvent_: function(permutation) {
281 var permutedEvent = new Event('permuted');
282 permutedEvent.newLength = this.length;
283 permutedEvent.permutation = permutation;
284 this.dispatchEvent(permutedEvent);
285
286 // Note: This model only fires 'permuted' event, because:
287 // 1) 'change' event is not necessary to fire since it is covered by
288 // 'permuted' event.
289 // 2) 'splice' and 'sorted' events are not implemented. These events are
290 // not used in NavigationListModel. We have to implement them when
291 // necessary.
292 }
293 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698