OLD | NEW |
---|---|
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 Loading... | |
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); |
OLD | NEW |