@ohos-ports/cross-storage 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +176 -0
- package/README.md +325 -0
- package/dist/client.js +465 -0
- package/dist/client.min.js +11 -0
- package/dist/hub.js +279 -0
- package/dist/hub.min.js +11 -0
- package/lib/client.js +629 -0
- package/lib/hub.js +299 -0
- package/lib/index.js +4 -0
- package/package.json +41 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cross-storage - Cross domain local storage
|
|
3
|
+
*
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
* @link https://github.com/zendesk/cross-storage
|
|
6
|
+
* @author Daniel St. Jules <danielst.jules@gmail.com>
|
|
7
|
+
* @copyright Zendesk
|
|
8
|
+
* @license Apache-2.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
;(function(root) {
|
|
12
|
+
/**
|
|
13
|
+
* Constructs a new cross storage client given the url to a hub. By default,
|
|
14
|
+
* an iframe is created within the document body that points to the url. It
|
|
15
|
+
* also accepts an options object, which may include a timeout, frameId, and
|
|
16
|
+
* promise. The timeout, in milliseconds, is applied to each request and
|
|
17
|
+
* defaults to 5000ms. The options object may also include a frameId,
|
|
18
|
+
* identifying an existing frame on which to install its listeners. If the
|
|
19
|
+
* promise key is supplied the constructor for a Promise, that Promise library
|
|
20
|
+
* will be used instead of the default window.Promise.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* var storage = new CrossStorageClient('https://store.example.com/hub.html');
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* var storage = new CrossStorageClient('https://store.example.com/hub.html', {
|
|
27
|
+
* timeout: 5000,
|
|
28
|
+
* frameId: 'storageFrame'
|
|
29
|
+
* });
|
|
30
|
+
*
|
|
31
|
+
* @constructor
|
|
32
|
+
*
|
|
33
|
+
* @param {string} url The url to a cross storage hub
|
|
34
|
+
* @param {object} [opts] An optional object containing additional options,
|
|
35
|
+
* including timeout, frameId, and promise
|
|
36
|
+
*
|
|
37
|
+
* @property {string} _id A UUID v4 id
|
|
38
|
+
* @property {function} _promise The Promise object to use
|
|
39
|
+
* @property {string} _frameId The id of the iFrame pointing to the hub url
|
|
40
|
+
* @property {string} _origin The hub's origin
|
|
41
|
+
* @property {object} _requests Mapping of request ids to callbacks
|
|
42
|
+
* @property {bool} _connected Whether or not it has connected
|
|
43
|
+
* @property {bool} _closed Whether or not the client has closed
|
|
44
|
+
* @property {int} _count Number of requests sent
|
|
45
|
+
* @property {function} _listener The listener added to the window
|
|
46
|
+
* @property {Window} _hub The hub window
|
|
47
|
+
*/
|
|
48
|
+
function CrossStorageClient(url, opts) {
|
|
49
|
+
opts = opts || {};
|
|
50
|
+
|
|
51
|
+
this._id = CrossStorageClient._generateUUID();
|
|
52
|
+
this._promise = opts.promise || Promise;
|
|
53
|
+
this._frameId = opts.frameId || 'CrossStorageClient-' + this._id;
|
|
54
|
+
this._origin = CrossStorageClient._getOrigin(url);
|
|
55
|
+
this._requests = {};
|
|
56
|
+
this._connected = false;
|
|
57
|
+
this._closed = false;
|
|
58
|
+
this._count = 0;
|
|
59
|
+
this._timeout = opts.timeout || 5000;
|
|
60
|
+
this._listener = null;
|
|
61
|
+
|
|
62
|
+
this._installListener();
|
|
63
|
+
|
|
64
|
+
var frame;
|
|
65
|
+
if (opts.frameId) {
|
|
66
|
+
frame = document.getElementById(opts.frameId);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If using a passed iframe, poll the hub for a ready message
|
|
70
|
+
if (frame) {
|
|
71
|
+
this._poll();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Create the frame if not found or specified
|
|
75
|
+
frame = frame || this._createFrame(url);
|
|
76
|
+
this._hub = frame.contentWindow;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The styles to be applied to the generated iFrame. Defines a set of properties
|
|
81
|
+
* that hide the element by positioning it outside of the visible area, and
|
|
82
|
+
* by modifying its display.
|
|
83
|
+
*
|
|
84
|
+
* @member {Object}
|
|
85
|
+
*/
|
|
86
|
+
CrossStorageClient.frameStyle = {
|
|
87
|
+
display: 'none',
|
|
88
|
+
position: 'absolute',
|
|
89
|
+
top: '-999px',
|
|
90
|
+
left: '-999px'
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Returns the origin of an url, with cross browser support. Accommodates
|
|
95
|
+
* the lack of location.origin in IE, as well as the discrepancies in the
|
|
96
|
+
* inclusion of the port when using the default port for a protocol, e.g.
|
|
97
|
+
* 443 over https. Defaults to the origin of window.location if passed a
|
|
98
|
+
* relative path.
|
|
99
|
+
*
|
|
100
|
+
* @param {string} url The url to a cross storage hub
|
|
101
|
+
* @returns {string} The origin of the url
|
|
102
|
+
*/
|
|
103
|
+
CrossStorageClient._getOrigin = function(url) {
|
|
104
|
+
var uri, protocol, origin;
|
|
105
|
+
|
|
106
|
+
uri = document.createElement('a');
|
|
107
|
+
uri.href = url;
|
|
108
|
+
|
|
109
|
+
if (!uri.host) {
|
|
110
|
+
uri = window.location;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (!uri.protocol || uri.protocol === ':') {
|
|
114
|
+
protocol = window.location.protocol;
|
|
115
|
+
} else {
|
|
116
|
+
protocol = uri.protocol;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
origin = protocol + '//' + uri.host;
|
|
120
|
+
origin = origin.replace(/:80$|:443$/, '');
|
|
121
|
+
|
|
122
|
+
return origin;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* UUID v4 generation, taken from: http://stackoverflow.com/questions/
|
|
127
|
+
* 105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
|
|
128
|
+
*
|
|
129
|
+
* @returns {string} A UUID v4 string
|
|
130
|
+
*/
|
|
131
|
+
CrossStorageClient._generateUUID = function() {
|
|
132
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
133
|
+
var r = Math.random() * 16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
|
134
|
+
|
|
135
|
+
return v.toString(16);
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns a promise that is fulfilled when a connection has been established
|
|
141
|
+
* with the cross storage hub. Its use is required to avoid sending any
|
|
142
|
+
* requests prior to initialization being complete.
|
|
143
|
+
*
|
|
144
|
+
* @returns {Promise} A promise that is resolved on connect
|
|
145
|
+
*/
|
|
146
|
+
CrossStorageClient.prototype.onConnect = function() {
|
|
147
|
+
var client = this;
|
|
148
|
+
|
|
149
|
+
if (this._connected) {
|
|
150
|
+
return this._promise.resolve();
|
|
151
|
+
} else if (this._closed) {
|
|
152
|
+
return this._promise.reject(new Error('CrossStorageClient has closed'));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Queue connect requests for client re-use
|
|
156
|
+
if (!this._requests.connect) {
|
|
157
|
+
this._requests.connect = [];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return new this._promise(function(resolve, reject) {
|
|
161
|
+
var timeout = setTimeout(function() {
|
|
162
|
+
reject(new Error('CrossStorageClient could not connect'));
|
|
163
|
+
}, client._timeout);
|
|
164
|
+
|
|
165
|
+
client._requests.connect.push(function(err) {
|
|
166
|
+
clearTimeout(timeout);
|
|
167
|
+
if (err) return reject(err);
|
|
168
|
+
|
|
169
|
+
resolve();
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Sets a key to the specified value. Returns a promise that is fulfilled on
|
|
176
|
+
* success, or rejected if any errors setting the key occurred, or the request
|
|
177
|
+
* timed out.
|
|
178
|
+
*
|
|
179
|
+
* @param {string} key The key to set
|
|
180
|
+
* @param {*} value The value to assign
|
|
181
|
+
* @returns {Promise} A promise that is settled on hub response or timeout
|
|
182
|
+
*/
|
|
183
|
+
CrossStorageClient.prototype.set = function(key, value) {
|
|
184
|
+
return this._request('set', {
|
|
185
|
+
key: key,
|
|
186
|
+
value: value
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Accepts one or more keys for which to retrieve their values. Returns a
|
|
192
|
+
* promise that is settled on hub response or timeout. On success, it is
|
|
193
|
+
* fulfilled with the value of the key if only passed a single argument.
|
|
194
|
+
* Otherwise it's resolved with an array of values. On failure, it is rejected
|
|
195
|
+
* with the corresponding error message.
|
|
196
|
+
*
|
|
197
|
+
* @param {...string} key The key to retrieve
|
|
198
|
+
* @returns {Promise} A promise that is settled on hub response or timeout
|
|
199
|
+
*/
|
|
200
|
+
CrossStorageClient.prototype.get = function(key) {
|
|
201
|
+
var args = Array.prototype.slice.call(arguments);
|
|
202
|
+
|
|
203
|
+
return this._request('get', {keys: args});
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Accepts one or more keys for deletion. Returns a promise that is settled on
|
|
208
|
+
* hub response or timeout.
|
|
209
|
+
*
|
|
210
|
+
* @param {...string} key The key to delete
|
|
211
|
+
* @returns {Promise} A promise that is settled on hub response or timeout
|
|
212
|
+
*/
|
|
213
|
+
CrossStorageClient.prototype.del = function() {
|
|
214
|
+
var args = Array.prototype.slice.call(arguments);
|
|
215
|
+
|
|
216
|
+
return this._request('del', {keys: args});
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Returns a promise that, when resolved, indicates that all localStorage
|
|
221
|
+
* data has been cleared.
|
|
222
|
+
*
|
|
223
|
+
* @returns {Promise} A promise that is settled on hub response or timeout
|
|
224
|
+
*/
|
|
225
|
+
CrossStorageClient.prototype.clear = function() {
|
|
226
|
+
return this._request('clear');
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Returns a promise that, when resolved, passes an array of all keys
|
|
231
|
+
* currently in storage.
|
|
232
|
+
*
|
|
233
|
+
* @returns {Promise} A promise that is settled on hub response or timeout
|
|
234
|
+
*/
|
|
235
|
+
CrossStorageClient.prototype.getKeys = function() {
|
|
236
|
+
return this._request('getKeys');
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Deletes the iframe and sets the connected state to false. The client can
|
|
241
|
+
* no longer be used after being invoked.
|
|
242
|
+
*/
|
|
243
|
+
CrossStorageClient.prototype.close = function() {
|
|
244
|
+
var frame = document.getElementById(this._frameId);
|
|
245
|
+
if (frame) {
|
|
246
|
+
frame.parentNode.removeChild(frame);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Support IE8 with detachEvent
|
|
250
|
+
if (window.removeEventListener) {
|
|
251
|
+
window.removeEventListener('message', this._listener, false);
|
|
252
|
+
} else {
|
|
253
|
+
window.detachEvent('onmessage', this._listener);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
this._connected = false;
|
|
257
|
+
this._closed = true;
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Installs the necessary listener for the window message event. When a message
|
|
262
|
+
* is received, the client's _connected status is changed to true, and the
|
|
263
|
+
* onConnect promise is fulfilled. Given a response message, the callback
|
|
264
|
+
* corresponding to its request is invoked. If response.error holds a truthy
|
|
265
|
+
* value, the promise associated with the original request is rejected with
|
|
266
|
+
* the error. Otherwise the promise is fulfilled and passed response.result.
|
|
267
|
+
*
|
|
268
|
+
* @private
|
|
269
|
+
*/
|
|
270
|
+
CrossStorageClient.prototype._installListener = function() {
|
|
271
|
+
var client = this;
|
|
272
|
+
|
|
273
|
+
this._listener = function(message) {
|
|
274
|
+
var i, origin, error, response;
|
|
275
|
+
|
|
276
|
+
// Ignore invalid messages or those after the client has closed
|
|
277
|
+
if (client._closed || !message.data || typeof message.data !== 'string') {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// postMessage returns the string "null" as the origin for "file://"
|
|
282
|
+
origin = (message.origin === 'null') ? 'file://' : message.origin;
|
|
283
|
+
|
|
284
|
+
// Ignore messages not from the correct origin
|
|
285
|
+
if (origin !== client._origin) return;
|
|
286
|
+
|
|
287
|
+
// LocalStorage isn't available in the hub
|
|
288
|
+
if (message.data === 'cross-storage:unavailable') {
|
|
289
|
+
if (!client._closed) client.close();
|
|
290
|
+
if (!client._requests.connect) return;
|
|
291
|
+
|
|
292
|
+
error = new Error('Closing client. Could not access localStorage in hub.');
|
|
293
|
+
for (i = 0; i < client._requests.connect.length; i++) {
|
|
294
|
+
client._requests.connect[i](error);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Handle initial connection
|
|
301
|
+
if (message.data.indexOf('cross-storage:') !== -1 && !client._connected) {
|
|
302
|
+
client._connected = true;
|
|
303
|
+
if (!client._requests.connect) return;
|
|
304
|
+
|
|
305
|
+
for (i = 0; i < client._requests.connect.length; i++) {
|
|
306
|
+
client._requests.connect[i](error);
|
|
307
|
+
}
|
|
308
|
+
delete client._requests.connect;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
if (message.data === 'cross-storage:ready') return;
|
|
312
|
+
|
|
313
|
+
// All other messages
|
|
314
|
+
try {
|
|
315
|
+
response = JSON.parse(message.data);
|
|
316
|
+
} catch(e) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!response.id) return;
|
|
321
|
+
|
|
322
|
+
if (client._requests[response.id]) {
|
|
323
|
+
client._requests[response.id](response.error, response.result);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// Support IE8 with attachEvent
|
|
328
|
+
if (window.addEventListener) {
|
|
329
|
+
window.addEventListener('message', this._listener, false);
|
|
330
|
+
} else {
|
|
331
|
+
window.attachEvent('onmessage', this._listener);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Invoked when a frame id was passed to the client, rather than allowing
|
|
337
|
+
* the client to create its own iframe. Polls the hub for a ready event to
|
|
338
|
+
* establish a connected state.
|
|
339
|
+
*/
|
|
340
|
+
CrossStorageClient.prototype._poll = function() {
|
|
341
|
+
var client, interval, targetOrigin;
|
|
342
|
+
|
|
343
|
+
client = this;
|
|
344
|
+
|
|
345
|
+
// postMessage requires that the target origin be set to "*" for "file://"
|
|
346
|
+
targetOrigin = (client._origin === 'file://') ? '*' : client._origin;
|
|
347
|
+
|
|
348
|
+
interval = setInterval(function() {
|
|
349
|
+
if (client._connected) return clearInterval(interval);
|
|
350
|
+
if (!client._hub) return;
|
|
351
|
+
|
|
352
|
+
client._hub.postMessage('cross-storage:poll', targetOrigin);
|
|
353
|
+
}, 1000);
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Creates a new iFrame containing the hub. Applies the necessary styles to
|
|
358
|
+
* hide the element from view, prior to adding it to the document body.
|
|
359
|
+
* Returns the created element.
|
|
360
|
+
*
|
|
361
|
+
* @private
|
|
362
|
+
*
|
|
363
|
+
* @param {string} url The url to the hub
|
|
364
|
+
* returns {HTMLIFrameElement} The iFrame element itself
|
|
365
|
+
*/
|
|
366
|
+
CrossStorageClient.prototype._createFrame = function(url) {
|
|
367
|
+
var frame, key;
|
|
368
|
+
|
|
369
|
+
frame = window.document.createElement('iframe');
|
|
370
|
+
frame.id = this._frameId;
|
|
371
|
+
|
|
372
|
+
// Style the iframe
|
|
373
|
+
for (key in CrossStorageClient.frameStyle) {
|
|
374
|
+
if (CrossStorageClient.frameStyle.hasOwnProperty(key)) {
|
|
375
|
+
frame.style[key] = CrossStorageClient.frameStyle[key];
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
window.document.body.appendChild(frame);
|
|
380
|
+
frame.src = url;
|
|
381
|
+
|
|
382
|
+
return frame;
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Sends a message containing the given method and params to the hub. Stores
|
|
387
|
+
* a callback in the _requests object for later invocation on message, or
|
|
388
|
+
* deletion on timeout. Returns a promise that is settled in either instance.
|
|
389
|
+
*
|
|
390
|
+
* @private
|
|
391
|
+
*
|
|
392
|
+
* @param {string} method The method to invoke
|
|
393
|
+
* @param {*} params The arguments to pass
|
|
394
|
+
* @returns {Promise} A promise that is settled on hub response or timeout
|
|
395
|
+
*/
|
|
396
|
+
CrossStorageClient.prototype._request = function(method, params) {
|
|
397
|
+
var req, client;
|
|
398
|
+
|
|
399
|
+
if (this._closed) {
|
|
400
|
+
return this._promise.reject(new Error('CrossStorageClient has closed'));
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
client = this;
|
|
404
|
+
client._count++;
|
|
405
|
+
|
|
406
|
+
req = {
|
|
407
|
+
id: this._id + ':' + client._count,
|
|
408
|
+
method: 'cross-storage:' + method,
|
|
409
|
+
params: params
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
return new this._promise(function(resolve, reject) {
|
|
413
|
+
var timeout, originalToJSON, targetOrigin;
|
|
414
|
+
|
|
415
|
+
// Timeout if a response isn't received after 4s
|
|
416
|
+
timeout = setTimeout(function() {
|
|
417
|
+
if (!client._requests[req.id]) return;
|
|
418
|
+
|
|
419
|
+
delete client._requests[req.id];
|
|
420
|
+
reject(new Error('Timeout: could not perform ' + req.method));
|
|
421
|
+
}, client._timeout);
|
|
422
|
+
|
|
423
|
+
// Add request callback
|
|
424
|
+
client._requests[req.id] = function(err, result) {
|
|
425
|
+
clearTimeout(timeout);
|
|
426
|
+
delete client._requests[req.id];
|
|
427
|
+
if (err) return reject(new Error(err));
|
|
428
|
+
resolve(result);
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// In case we have a broken Array.prototype.toJSON, e.g. because of
|
|
432
|
+
// old versions of prototype
|
|
433
|
+
if (Array.prototype.toJSON) {
|
|
434
|
+
originalToJSON = Array.prototype.toJSON;
|
|
435
|
+
Array.prototype.toJSON = null;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// postMessage requires that the target origin be set to "*" for "file://"
|
|
439
|
+
targetOrigin = (client._origin === 'file://') ? '*' : client._origin;
|
|
440
|
+
|
|
441
|
+
// Send serialized message
|
|
442
|
+
client._hub.postMessage(JSON.stringify(req), targetOrigin);
|
|
443
|
+
|
|
444
|
+
// Restore original toJSON
|
|
445
|
+
if (originalToJSON) {
|
|
446
|
+
Array.prototype.toJSON = originalToJSON;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Export for various environments.
|
|
453
|
+
*/
|
|
454
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
455
|
+
module.exports = CrossStorageClient;
|
|
456
|
+
} else if (typeof exports !== 'undefined') {
|
|
457
|
+
exports.CrossStorageClient = CrossStorageClient;
|
|
458
|
+
} else if (typeof define === 'function' && define.amd) {
|
|
459
|
+
define([], function() {
|
|
460
|
+
return CrossStorageClient;
|
|
461
|
+
});
|
|
462
|
+
} else {
|
|
463
|
+
root.CrossStorageClient = CrossStorageClient;
|
|
464
|
+
}
|
|
465
|
+
}(this));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cross-storage - Cross domain local storage
|
|
3
|
+
*
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
* @link https://github.com/zendesk/cross-storage
|
|
6
|
+
* @author Daniel St. Jules <danielst.jules@gmail.com>
|
|
7
|
+
* @copyright Zendesk
|
|
8
|
+
* @license Apache-2.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
!function(e){function t(e,r){r=r||{},this._id=t._generateUUID(),this._promise=r.promise||Promise,this._frameId=r.frameId||"CrossStorageClient-"+this._id,this._origin=t._getOrigin(e),this._requests={},this._connected=!1,this._closed=!1,this._count=0,this._timeout=r.timeout||5e3,this._listener=null,this._installListener();var o;r.frameId&&(o=document.getElementById(r.frameId)),o&&this._poll(),o=o||this._createFrame(e),this._hub=o.contentWindow}t.frameStyle={display:"none",position:"absolute",top:"-999px",left:"-999px"},t._getOrigin=function(e){var t,r,o;return t=document.createElement("a"),t.href=e,t.host||(t=window.location),r=t.protocol&&":"!==t.protocol?t.protocol:window.location.protocol,o=r+"//"+t.host,o=o.replace(/:80$|:443$/,"")},t._generateUUID=function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(e){var t=16*Math.random()|0,r="x"==e?t:3&t|8;return r.toString(16)})},t.prototype.onConnect=function(){var e=this;return this._connected?this._promise.resolve():this._closed?this._promise.reject(new Error("CrossStorageClient has closed")):(this._requests.connect||(this._requests.connect=[]),new this._promise(function(t,r){var o=setTimeout(function(){r(new Error("CrossStorageClient could not connect"))},e._timeout);e._requests.connect.push(function(e){return clearTimeout(o),e?r(e):(t(),void 0)})}))},t.prototype.set=function(e,t){return this._request("set",{key:e,value:t})},t.prototype.get=function(){var e=Array.prototype.slice.call(arguments);return this._request("get",{keys:e})},t.prototype.del=function(){var e=Array.prototype.slice.call(arguments);return this._request("del",{keys:e})},t.prototype.clear=function(){return this._request("clear")},t.prototype.getKeys=function(){return this._request("getKeys")},t.prototype.close=function(){var e=document.getElementById(this._frameId);e&&e.parentNode.removeChild(e),window.removeEventListener?window.removeEventListener("message",this._listener,!1):window.detachEvent("onmessage",this._listener),this._connected=!1,this._closed=!0},t.prototype._installListener=function(){var e=this;this._listener=function(t){var r,o,n,s;if(!e._closed&&t.data&&"string"==typeof t.data&&(o="null"===t.origin?"file://":t.origin,o===e._origin))if("cross-storage:unavailable"!==t.data){if(-1!==t.data.indexOf("cross-storage:")&&!e._connected){if(e._connected=!0,!e._requests.connect)return;for(r=0;r<e._requests.connect.length;r++)e._requests.connect[r](n);delete e._requests.connect}if("cross-storage:ready"!==t.data){try{s=JSON.parse(t.data)}catch(i){return}s.id&&e._requests[s.id]&&e._requests[s.id](s.error,s.result)}}else{if(e._closed||e.close(),!e._requests.connect)return;for(n=new Error("Closing client. Could not access localStorage in hub."),r=0;r<e._requests.connect.length;r++)e._requests.connect[r](n)}},window.addEventListener?window.addEventListener("message",this._listener,!1):window.attachEvent("onmessage",this._listener)},t.prototype._poll=function(){var e,t,r;e=this,r="file://"===e._origin?"*":e._origin,t=setInterval(function(){return e._connected?clearInterval(t):(e._hub&&e._hub.postMessage("cross-storage:poll",r),void 0)},1e3)},t.prototype._createFrame=function(e){var r,o;r=window.document.createElement("iframe"),r.id=this._frameId;for(o in t.frameStyle)t.frameStyle.hasOwnProperty(o)&&(r.style[o]=t.frameStyle[o]);return window.document.body.appendChild(r),r.src=e,r},t.prototype._request=function(e,t){var r,o;return this._closed?this._promise.reject(new Error("CrossStorageClient has closed")):(o=this,o._count++,r={id:this._id+":"+o._count,method:"cross-storage:"+e,params:t},new this._promise(function(e,t){var n,s,i;n=setTimeout(function(){o._requests[r.id]&&(delete o._requests[r.id],t(new Error("Timeout: could not perform "+r.method)))},o._timeout),o._requests[r.id]=function(s,i){return clearTimeout(n),delete o._requests[r.id],s?t(new Error(s)):(e(i),void 0)},Array.prototype.toJSON&&(s=Array.prototype.toJSON,Array.prototype.toJSON=null),i="file://"===o._origin?"*":o._origin,o._hub.postMessage(JSON.stringify(r),i),s&&(Array.prototype.toJSON=s)}))},"undefined"!=typeof module&&module.exports?module.exports=t:"undefined"!=typeof exports?exports.CrossStorageClient=t:"function"==typeof define&&define.amd?define([],function(){return t}):e.CrossStorageClient=t}(this);
|