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

Side by Side Diff: src/js/polyfills/storage.polyfill.js

Issue 1593443003: Finished storage polyfill. (Closed) Base URL: sso://user/alger/caterpillar@master
Patch Set: Created 4 years, 11 months 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
OLDNEW
1 // Copyright 2015 Google Inc. All Rights Reserved. 1 // Copyright 2015 Google Inc. All Rights Reserved.
2 // 2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License. 4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at 5 // You may obtain a copy of the License at
6 // 6 //
7 // http://www.apache.org/licenses/LICENSE-2.0 7 // http://www.apache.org/licenses/LICENSE-2.0
8 // 8 //
9 // Unless required by applicable law or agreed to in writing, software 9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, 10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and 12 // See the License for the specific language governing permissions and
13 // limitations under the License. 13 // limitations under the License.
14 14
15 /** 15 /**
16 * Polyfill for Chrome Apps' storage API. 16 * Polyfill for Chrome Apps' storage API.
17 */ 17 */
18 18
19 'use strict'; 19 'use strict';
20 20
21 if (!chrome.storage) 21 if (!chrome.storage)
22 chrome.storage = {}; 22 chrome.storage = {};
23 23
24 chrome.caterpillar.storage = {};
25
24 (function() { 26 (function() {
25 27
26 /** 28 /**
27 * Triggers a chrome.storage.onChanged event on self. 29 * Triggers a chrome.storage.onChanged event on self.
28 * 30 *
29 * This is used internally within the polyfill to manage change events; event 31 * This is used internally within the polyfill to manage change events; event
30 * information is stored in event.detail. 32 * information is stored in event.detail.
31 * 33 *
32 * @param {object} items Object mapping keys to StorageChanges containing the 34 * @param {object} items Object mapping keys to StorageChanges containing the
33 * new and old values of each item. 35 * new and old values of each item.
34 */ 36 */
35 function triggerOnChanged(items) { 37 function triggerOnChanged(items) {
36 var event = new CustomEvent('chrome.storage.onChanged', {'detail': items}); 38 var event = new CustomEvent('chrome.storage.onChanged', {'detail': items});
37 self.dispatchEvent(event); 39 self.dispatchEvent(event);
38 }; 40 };
39 41
40 /** 42 /**
43 * Stores onChanged event listeners.
44 */
45 var onChangedListeners = [];
46
47 /**
41 * Represents a change in stored data. 48 * Represents a change in stored data.
42 */ 49 */
43 chrome.storage.StorageChange = class { 50 chrome.storage.StorageChange = class {
44 /** 51 /**
45 * @param {object=} opt_oldValue The old value of the item. 52 * @param {object=} opt_oldValue The old value of the item.
46 * @param {object=} opt_newValue The new value of the item. 53 * @param {object=} opt_newValue The new value of the item.
47 */ 54 */
48 constructor(opt_oldValue, opt_newValue) { 55 constructor(opt_oldValue, opt_newValue) {
49 this.oldValue = opt_oldValue; 56 this.oldValue = opt_oldValue;
50 this.newValue = opt_newValue; 57 this.newValue = opt_newValue;
51 }; 58 }
52 }; 59 };
53 60
54 /** 61 /**
55 * Represents an area where data can be stored. 62 * Represents an area where data can be stored.
56 * 63 *
57 * Chrome Apps have three such areas - sync, local, managed. 64 * Chrome Apps have three such areas - sync, local, managed.
58 */ 65 */
59 chrome.storage.StorageArea = class { 66 chrome.storage.StorageArea = class {
60 /** 67 /**
61 * Gets one or more items from storage. 68 * Gets one or more items from storage.
62 * 69 *
63 * @param {string | string[] | object} opt_keys A single key to get, list 70 * @param {string= | string[]= | object=} opt_keys A single key to get, list
64 * of keys to get, or a dictionary specifying default values. Empty lists 71 * of keys to get, or a dictionary specifying default values. Empty lists
65 * or objects return empty results. Pass null to get all contents. 72 * or objects return empty results. Pass null to get all contents.
66 * @param {function} callback Callback with storage items, or on failure. 73 * @param {function} callback Callback with storage items, or on failure.
67 */ 74 */
68 get(opt_keys, callback) { 75 get(opt_keys, callback) {
69 // Handle the optional argument being *first*. 76 // Juggle arguments.
70 if (callback === undefined) { 77 if (callback === undefined) {
71 // Keys wasn't actually given, the callback was. 78 // Keys wasn't actually given, the callback was.
72 callback = opt_keys; 79 callback = opt_keys;
73 opt_keys = null; 80 opt_keys = null;
74 } 81 }
75 82
76 // Four scenarios: 83 // Four scenarios:
77 // 1. Input is a single string key; retrieve associated value. 84 // 1. Input is a single string key; retrieve associated value.
78 // 2. Input is multiple string keys; retrieve associated values. 85 // 2. Input is multiple string keys; retrieve associated values.
79 // 3. Input is a map from string key to default value; retrieve associated 86 // 3. Input is a map from string key to default value; retrieve associated
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 items[keys[i]] = opt_keys[keys[i]]; 130 items[keys[i]] = opt_keys[keys[i]];
124 } else { 131 } else {
125 items[keys[i]] = values[i]; 132 items[keys[i]] = values[i];
126 } 133 }
127 } 134 }
128 callback(items); 135 callback(items);
129 }) 136 })
130 .catch(handleError); 137 .catch(handleError);
131 } 138 }
132 } 139 }
140
141 /**
142 * Gets the amount of space (in bytes) being used by one or more items.
143 *
144 * Not implemented in this polyfill.
145 *
146 * @param {string= | string[]= | object=} opt_keys A single key to get,
147 * list of keys to get, or a dictionary specifying default values. Empty
raymes 2016/01/18 00:25:20 nit: 4 space indent (here and below)
Matthew Alger 2016/01/18 00:37:37 Done.
148 * lists or objects return 0. Pass null to get total usage.
149 * @param {function} callback Callback with bytes in use, or failure.
150 */
151 getBytesInUse(opt_keys, callback) {
152 // Juggle arguments.
153 if (callback === undefined) {
154 callback = opt_keys;
155 opt_keys = null;
156 }
157 // IndexedDB doesn't support this, so neither does localforage.
158 chrome.caterpillar.setError('getBytesInUse not implemented.');
159 callback();
160 }
161
162 /**
163 * Sets multiple items.
164 *
165 * @param {object} items An object which gives key/value pairs to update
166 * storage with. Other key/value pairs in storage will not be affected.
167 * @param {function=} opt_callback Callback on success or failure.
168 */
169 set(items, opt_callback) {
170 var keys = Object.keys(items);
171 try {
172 // We need to trigger an event containing all the old values and new value s.
173 // To do that, we first need the old values.
174 this.get(keys, function (oldItems) {
175 // Now that we have the old values, we can set the new values.
176 Promise.all(keys.map(key => localforage.setItem(key, items[key])))
177 // Then setup the input and trigger the event.
178 .then(function() {
179 var changes = {};
180 for (var key of keys) {
181 changes[key] = new chrome.storage.StorageChange(
182 oldItems[key], items[key]);
183 }
184 triggerOnChanged(changes);
185 if (opt_callback !== undefined)
186 opt_callback();
187 });
188 });
189 } catch (e) {
190 chrome.caterpillar.setError('Error setting values: ' + (e.message || e));
191 opt_callback();
raymes 2016/01/18 00:25:20 what if opt_callback is undefined?
Matthew Alger 2016/01/18 00:37:37 Done.
192 }
193 }
194
195 /**
196 * Removes one or more items from storage.
197 *
198 * @param {string || string[]} keys A single key or a list of keys to
199 * remove.
200 * @param {function=} opt_callback Callback on success or failure.
201 */
202 remove(keys, opt_callback) {
203 var handleError = function(err) {
204 chrome.caterpillar.setError('Error removing keys: ' + err);
205 opt_callback();
raymes 2016/01/18 00:25:20 what if opt_callback is undefined?
Matthew Alger 2016/01/18 00:37:37 Done.
206 };
207 try {
208 this.get(keys, function(items) {
209 if (Array.isArray(keys)) {
raymes 2016/01/18 00:25:20 If keys is a string, you could turn it into an arr
Matthew Alger 2016/01/18 00:37:37 Oh, good idea! Done, and done in get too.
210 Promise.all(keys.map(key => localforage.removeItem(key)))
211 .then(function() {
212 var changes = {};
213 for (var key of keys) {
214 changes[key] = new chrome.storage.StorageChange(
215 items[key], null);
216 }
217 triggerOnChanged(changes);
218 opt_callback();
raymes 2016/01/18 00:25:20 what if opt_callback is undefined?
Matthew Alger 2016/01/18 00:37:37 Done.
219 })
220 } else {
221 localforage.removeItem(keys).then(function() {
222 var changes = {};
223 changes[keys] = new chrome.storage.StorageChange(
224 items[keys], null);
225 triggerOnChanged(changes);
226 opt_callback();
227 });
228 }
229 });
230 } catch (e) {
231 handleError(e.message || e);
232 }
233 }
234
235 /**
236 * Removes all items from storage.
237 *
238 * @param {function=} opt_callback Callback on success or failure.
239 */
240 clear(opt_callback) {
241 try {
242 this.get(function(items) {
243 var changes = {};
244 for (var key in items) {
245 changes[key] = new chrome.storage.StorageChange(items[key], null);
246 }
247 triggerOnChanged(changes);
248 localforage.clear(opt_callback);
raymes 2016/01/18 00:25:20 I think it's probably better to clear things befor
Matthew Alger 2016/01/18 00:37:37 Do you mean it's better to clear things before the
249 });
250 } catch (e) {
251 chrome.caterpillar.setError('Error clearing values: ' + (e.message || e));
252 if (opt_callback)
raymes 2016/01/18 00:25:20 This is inconsistent with other places where you h
Matthew Alger 2016/01/18 00:37:37 Changed everything to just check opt_callback's tr
253 opt_callback();
254 }
255 }
133 }; 256 };
134 257
135 /** 258 /**
136 * Items in the local storage area are stored locally. 259 * Items in the local storage area are stored locally.
137 */ 260 */
138 chrome.storage.local = new chrome.storage.StorageArea(); 261 chrome.storage.local = new chrome.storage.StorageArea();
139 262
140 /** 263 /**
141 * Items in the sync storage area would be synced using Chrome Sync; in this 264 * Items in the sync storage area would be synced using Chrome Sync; in this
142 * polyfill we just use local storage. 265 * polyfill we just use local storage.
143 */ 266 */
144 chrome.storage.sync = chrome.storage.local; 267 chrome.storage.sync = chrome.storage.local;
145 268
146 /** 269 /**
147 * Items in the managed storage area are read-only usually; in this polyfill 270 * Items in the managed storage area are read-only usually; in this polyfill
148 * managed is the same as local storage. 271 * managed is the same as local storage.
149 */ 272 */
150 chrome.storage.managed = chrome.storage.local; 273 chrome.storage.managed = chrome.storage.local;
151 274
152 /** 275 /**
153 * Namespace. 276 * Namespace.
154 */ 277 */
155 chrome.storage.onChanged = {}; 278 chrome.storage.onChanged = {};
156 279
157 /** 280 /**
158 * Adds an event listener for the onChanged event. 281 * Adds an event listener for the onChanged event.
159 * 282 *
160 * @param {function} callback Function taking a changes object of key/value 283 * @param {function} callback Function taking an object mapping changed keys to
161 * pairs. 284 * StorageChanges and an area name (though the latter will always be null).
162 */ 285 */
163 chrome.storage.onChanged.addListener = function(callback) { 286 chrome.storage.onChanged.addListener = function(callback) {
164 self.addEventListener('chrome.storage.onChanged', e => { 287 var listener = function(e) {
165 callback(e.detail); 288 callback(e.detail, null);
166 }); 289 };
290
291 self.addEventListener('chrome.storage.onChanged', listener);
292 onChangedListeners.push(listener);
293 };
294
295 /**
296 * Resets onChanged event listeners. Used for testing.
297 */
298 chrome.caterpillar.storage.resetOnChangedListenersForTests = function() {
299 for (var listener of onChangedListeners) {
300 self.removeEventListener('chrome.storage.onChanged', listener);
301 }
302
303 onChangedListeners.length = 0;
167 }; 304 };
168 305
169 }).call(this); 306 }).call(this);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698