Fix actions/tour
This commit is contained in:
1116
node_modules/localforage/src/drivers/indexeddb.js
generated
vendored
Normal file
1116
node_modules/localforage/src/drivers/indexeddb.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
332
node_modules/localforage/src/drivers/localstorage.js
generated
vendored
Normal file
332
node_modules/localforage/src/drivers/localstorage.js
generated
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
// If IndexedDB isn't available, we'll fall back to localStorage.
|
||||
// Note that this will have considerable performance and storage
|
||||
// side-effects (all data will be serialized on save and only data that
|
||||
// can be converted to a string via `JSON.stringify()` will be saved).
|
||||
|
||||
import isLocalStorageValid from '../utils/isLocalStorageValid';
|
||||
import serializer from '../utils/serializer';
|
||||
import Promise from '../utils/promise';
|
||||
import executeCallback from '../utils/executeCallback';
|
||||
import normalizeKey from '../utils/normalizeKey';
|
||||
import getCallback from '../utils/getCallback';
|
||||
|
||||
function _getKeyPrefix(options, defaultConfig) {
|
||||
var keyPrefix = options.name + '/';
|
||||
|
||||
if (options.storeName !== defaultConfig.storeName) {
|
||||
keyPrefix += options.storeName + '/';
|
||||
}
|
||||
return keyPrefix;
|
||||
}
|
||||
|
||||
// Check if localStorage throws when saving an item
|
||||
function checkIfLocalStorageThrows() {
|
||||
var localStorageTestKey = '_localforage_support_test';
|
||||
|
||||
try {
|
||||
localStorage.setItem(localStorageTestKey, true);
|
||||
localStorage.removeItem(localStorageTestKey);
|
||||
|
||||
return false;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if localStorage is usable and allows to save an item
|
||||
// This method checks if localStorage is usable in Safari Private Browsing
|
||||
// mode, or in any other case where the available quota for localStorage
|
||||
// is 0 and there wasn't any saved items yet.
|
||||
function _isLocalStorageUsable() {
|
||||
return !checkIfLocalStorageThrows() || localStorage.length > 0;
|
||||
}
|
||||
|
||||
// Config the localStorage backend, using options set in the config.
|
||||
function _initStorage(options) {
|
||||
var self = this;
|
||||
var dbInfo = {};
|
||||
if (options) {
|
||||
for (var i in options) {
|
||||
dbInfo[i] = options[i];
|
||||
}
|
||||
}
|
||||
|
||||
dbInfo.keyPrefix = _getKeyPrefix(options, self._defaultConfig);
|
||||
|
||||
if (!_isLocalStorageUsable()) {
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
self._dbInfo = dbInfo;
|
||||
dbInfo.serializer = serializer;
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Remove all keys from the datastore, effectively destroying all data in
|
||||
// the app's key/value store!
|
||||
function clear(callback) {
|
||||
var self = this;
|
||||
var promise = self.ready().then(function() {
|
||||
var keyPrefix = self._dbInfo.keyPrefix;
|
||||
|
||||
for (var i = localStorage.length - 1; i >= 0; i--) {
|
||||
var key = localStorage.key(i);
|
||||
|
||||
if (key.indexOf(keyPrefix) === 0) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Retrieve an item from the store. Unlike the original async_storage
|
||||
// library in Gaia, we don't modify return values at all. If a key's value
|
||||
// is `undefined`, we pass that value to the callback function.
|
||||
function getItem(key, callback) {
|
||||
var self = this;
|
||||
|
||||
key = normalizeKey(key);
|
||||
|
||||
var promise = self.ready().then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
var result = localStorage.getItem(dbInfo.keyPrefix + key);
|
||||
|
||||
// If a result was found, parse it from the serialized
|
||||
// string into a JS object. If result isn't truthy, the key
|
||||
// is likely undefined and we'll pass it straight to the
|
||||
// callback.
|
||||
if (result) {
|
||||
result = dbInfo.serializer.deserialize(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Iterate over all items in the store.
|
||||
function iterate(iterator, callback) {
|
||||
var self = this;
|
||||
|
||||
var promise = self.ready().then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
var keyPrefix = dbInfo.keyPrefix;
|
||||
var keyPrefixLength = keyPrefix.length;
|
||||
var length = localStorage.length;
|
||||
|
||||
// We use a dedicated iterator instead of the `i` variable below
|
||||
// so other keys we fetch in localStorage aren't counted in
|
||||
// the `iterationNumber` argument passed to the `iterate()`
|
||||
// callback.
|
||||
//
|
||||
// See: github.com/mozilla/localForage/pull/435#discussion_r38061530
|
||||
var iterationNumber = 1;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
var key = localStorage.key(i);
|
||||
if (key.indexOf(keyPrefix) !== 0) {
|
||||
continue;
|
||||
}
|
||||
var value = localStorage.getItem(key);
|
||||
|
||||
// If a result was found, parse it from the serialized
|
||||
// string into a JS object. If result isn't truthy, the
|
||||
// key is likely undefined and we'll pass it straight
|
||||
// to the iterator.
|
||||
if (value) {
|
||||
value = dbInfo.serializer.deserialize(value);
|
||||
}
|
||||
|
||||
value = iterator(
|
||||
value,
|
||||
key.substring(keyPrefixLength),
|
||||
iterationNumber++
|
||||
);
|
||||
|
||||
if (value !== void 0) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Same as localStorage's key() method, except takes a callback.
|
||||
function key(n, callback) {
|
||||
var self = this;
|
||||
var promise = self.ready().then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
var result;
|
||||
try {
|
||||
result = localStorage.key(n);
|
||||
} catch (error) {
|
||||
result = null;
|
||||
}
|
||||
|
||||
// Remove the prefix from the key, if a key is found.
|
||||
if (result) {
|
||||
result = result.substring(dbInfo.keyPrefix.length);
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function keys(callback) {
|
||||
var self = this;
|
||||
var promise = self.ready().then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
var length = localStorage.length;
|
||||
var keys = [];
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
var itemKey = localStorage.key(i);
|
||||
if (itemKey.indexOf(dbInfo.keyPrefix) === 0) {
|
||||
keys.push(itemKey.substring(dbInfo.keyPrefix.length));
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Supply the number of keys in the datastore to the callback function.
|
||||
function length(callback) {
|
||||
var self = this;
|
||||
var promise = self.keys().then(function(keys) {
|
||||
return keys.length;
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Remove an item from the store, nice and simple.
|
||||
function removeItem(key, callback) {
|
||||
var self = this;
|
||||
|
||||
key = normalizeKey(key);
|
||||
|
||||
var promise = self.ready().then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
localStorage.removeItem(dbInfo.keyPrefix + key);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Set a key's value and run an optional callback once the value is set.
|
||||
// Unlike Gaia's implementation, the callback function is passed the value,
|
||||
// in case you want to operate on that value only after you're sure it
|
||||
// saved, or something like that.
|
||||
function setItem(key, value, callback) {
|
||||
var self = this;
|
||||
|
||||
key = normalizeKey(key);
|
||||
|
||||
var promise = self.ready().then(function() {
|
||||
// Convert undefined values to null.
|
||||
// https://github.com/mozilla/localForage/pull/42
|
||||
if (value === undefined) {
|
||||
value = null;
|
||||
}
|
||||
|
||||
// Save the original value to pass to the callback.
|
||||
var originalValue = value;
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.serializer.serialize(value, function(value, error) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
try {
|
||||
localStorage.setItem(dbInfo.keyPrefix + key, value);
|
||||
resolve(originalValue);
|
||||
} catch (e) {
|
||||
// localStorage capacity exceeded.
|
||||
// TODO: Make this a specific error/event.
|
||||
if (
|
||||
e.name === 'QuotaExceededError' ||
|
||||
e.name === 'NS_ERROR_DOM_QUOTA_REACHED'
|
||||
) {
|
||||
reject(e);
|
||||
}
|
||||
reject(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function dropInstance(options, callback) {
|
||||
callback = getCallback.apply(this, arguments);
|
||||
|
||||
options = (typeof options !== 'function' && options) || {};
|
||||
if (!options.name) {
|
||||
var currentConfig = this.config();
|
||||
options.name = options.name || currentConfig.name;
|
||||
options.storeName = options.storeName || currentConfig.storeName;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var promise;
|
||||
if (!options.name) {
|
||||
promise = Promise.reject('Invalid arguments');
|
||||
} else {
|
||||
promise = new Promise(function(resolve) {
|
||||
if (!options.storeName) {
|
||||
resolve(`${options.name}/`);
|
||||
} else {
|
||||
resolve(_getKeyPrefix(options, self._defaultConfig));
|
||||
}
|
||||
}).then(function(keyPrefix) {
|
||||
for (var i = localStorage.length - 1; i >= 0; i--) {
|
||||
var key = localStorage.key(i);
|
||||
|
||||
if (key.indexOf(keyPrefix) === 0) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
var localStorageWrapper = {
|
||||
_driver: 'localStorageWrapper',
|
||||
_initStorage: _initStorage,
|
||||
_support: isLocalStorageValid(),
|
||||
iterate: iterate,
|
||||
getItem: getItem,
|
||||
setItem: setItem,
|
||||
removeItem: removeItem,
|
||||
clear: clear,
|
||||
length: length,
|
||||
key: key,
|
||||
keys: keys,
|
||||
dropInstance: dropInstance
|
||||
};
|
||||
|
||||
export default localStorageWrapper;
|
||||
610
node_modules/localforage/src/drivers/websql.js
generated
vendored
Normal file
610
node_modules/localforage/src/drivers/websql.js
generated
vendored
Normal file
@@ -0,0 +1,610 @@
|
||||
import isWebSQLValid from '../utils/isWebSQLValid';
|
||||
import serializer from '../utils/serializer';
|
||||
import Promise from '../utils/promise';
|
||||
import executeCallback from '../utils/executeCallback';
|
||||
import normalizeKey from '../utils/normalizeKey';
|
||||
import getCallback from '../utils/getCallback';
|
||||
|
||||
/*
|
||||
* Includes code from:
|
||||
*
|
||||
* base64-arraybuffer
|
||||
* https://github.com/niklasvh/base64-arraybuffer
|
||||
*
|
||||
* Copyright (c) 2012 Niklas von Hertzen
|
||||
* Licensed under the MIT license.
|
||||
*/
|
||||
|
||||
function createDbTable(t, dbInfo, callback, errorCallback) {
|
||||
t.executeSql(
|
||||
`CREATE TABLE IF NOT EXISTS ${dbInfo.storeName} ` +
|
||||
'(id INTEGER PRIMARY KEY, key unique, value)',
|
||||
[],
|
||||
callback,
|
||||
errorCallback
|
||||
);
|
||||
}
|
||||
|
||||
// Open the WebSQL database (automatically creates one if one didn't
|
||||
// previously exist), using any options set in the config.
|
||||
function _initStorage(options) {
|
||||
var self = this;
|
||||
var dbInfo = {
|
||||
db: null
|
||||
};
|
||||
|
||||
if (options) {
|
||||
for (var i in options) {
|
||||
dbInfo[i] =
|
||||
typeof options[i] !== 'string'
|
||||
? options[i].toString()
|
||||
: options[i];
|
||||
}
|
||||
}
|
||||
|
||||
var dbInfoPromise = new Promise(function(resolve, reject) {
|
||||
// Open the database; the openDatabase API will automatically
|
||||
// create it for us if it doesn't exist.
|
||||
try {
|
||||
dbInfo.db = openDatabase(
|
||||
dbInfo.name,
|
||||
String(dbInfo.version),
|
||||
dbInfo.description,
|
||||
dbInfo.size
|
||||
);
|
||||
} catch (e) {
|
||||
return reject(e);
|
||||
}
|
||||
|
||||
// Create our key/value table if it doesn't exist.
|
||||
dbInfo.db.transaction(function(t) {
|
||||
createDbTable(
|
||||
t,
|
||||
dbInfo,
|
||||
function() {
|
||||
self._dbInfo = dbInfo;
|
||||
resolve();
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
}, reject);
|
||||
});
|
||||
|
||||
dbInfo.serializer = serializer;
|
||||
return dbInfoPromise;
|
||||
}
|
||||
|
||||
function tryExecuteSql(t, dbInfo, sqlStatement, args, callback, errorCallback) {
|
||||
t.executeSql(
|
||||
sqlStatement,
|
||||
args,
|
||||
callback,
|
||||
function(t, error) {
|
||||
if (error.code === error.SYNTAX_ERR) {
|
||||
t.executeSql(
|
||||
'SELECT name FROM sqlite_master ' +
|
||||
"WHERE type='table' AND name = ?",
|
||||
[dbInfo.storeName],
|
||||
function(t, results) {
|
||||
if (!results.rows.length) {
|
||||
// if the table is missing (was deleted)
|
||||
// re-create it table and retry
|
||||
createDbTable(
|
||||
t,
|
||||
dbInfo,
|
||||
function() {
|
||||
t.executeSql(
|
||||
sqlStatement,
|
||||
args,
|
||||
callback,
|
||||
errorCallback
|
||||
);
|
||||
},
|
||||
errorCallback
|
||||
);
|
||||
} else {
|
||||
errorCallback(t, error);
|
||||
}
|
||||
},
|
||||
errorCallback
|
||||
);
|
||||
} else {
|
||||
errorCallback(t, error);
|
||||
}
|
||||
},
|
||||
errorCallback
|
||||
);
|
||||
}
|
||||
|
||||
function getItem(key, callback) {
|
||||
var self = this;
|
||||
|
||||
key = normalizeKey(key);
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.db.transaction(function(t) {
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`SELECT * FROM ${
|
||||
dbInfo.storeName
|
||||
} WHERE key = ? LIMIT 1`,
|
||||
[key],
|
||||
function(t, results) {
|
||||
var result = results.rows.length
|
||||
? results.rows.item(0).value
|
||||
: null;
|
||||
|
||||
// Check to see if this is serialized content we need to
|
||||
// unpack.
|
||||
if (result) {
|
||||
result = dbInfo.serializer.deserialize(result);
|
||||
}
|
||||
|
||||
resolve(result);
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function iterate(iterator, callback) {
|
||||
var self = this;
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
|
||||
dbInfo.db.transaction(function(t) {
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`SELECT * FROM ${dbInfo.storeName}`,
|
||||
[],
|
||||
function(t, results) {
|
||||
var rows = results.rows;
|
||||
var length = rows.length;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
var item = rows.item(i);
|
||||
var result = item.value;
|
||||
|
||||
// Check to see if this is serialized content
|
||||
// we need to unpack.
|
||||
if (result) {
|
||||
result = dbInfo.serializer.deserialize(
|
||||
result
|
||||
);
|
||||
}
|
||||
|
||||
result = iterator(result, item.key, i + 1);
|
||||
|
||||
// void(0) prevents problems with redefinition
|
||||
// of `undefined`.
|
||||
if (result !== void 0) {
|
||||
resolve(result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resolve();
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function _setItem(key, value, callback, retriesLeft) {
|
||||
var self = this;
|
||||
|
||||
key = normalizeKey(key);
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
// The localStorage API doesn't return undefined values in an
|
||||
// "expected" way, so undefined is always cast to null in all
|
||||
// drivers. See: https://github.com/mozilla/localForage/pull/42
|
||||
if (value === undefined) {
|
||||
value = null;
|
||||
}
|
||||
|
||||
// Save the original value to pass to the callback.
|
||||
var originalValue = value;
|
||||
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.serializer.serialize(value, function(value, error) {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
dbInfo.db.transaction(
|
||||
function(t) {
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`INSERT OR REPLACE INTO ${
|
||||
dbInfo.storeName
|
||||
} ` + '(key, value) VALUES (?, ?)',
|
||||
[key, value],
|
||||
function() {
|
||||
resolve(originalValue);
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
function(sqlError) {
|
||||
// The transaction failed; check
|
||||
// to see if it's a quota error.
|
||||
if (sqlError.code === sqlError.QUOTA_ERR) {
|
||||
// We reject the callback outright for now, but
|
||||
// it's worth trying to re-run the transaction.
|
||||
// Even if the user accepts the prompt to use
|
||||
// more storage on Safari, this error will
|
||||
// be called.
|
||||
//
|
||||
// Try to re-run the transaction.
|
||||
if (retriesLeft > 0) {
|
||||
resolve(
|
||||
_setItem.apply(self, [
|
||||
key,
|
||||
originalValue,
|
||||
callback,
|
||||
retriesLeft - 1
|
||||
])
|
||||
);
|
||||
return;
|
||||
}
|
||||
reject(sqlError);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function setItem(key, value, callback) {
|
||||
return _setItem.apply(this, [key, value, callback, 1]);
|
||||
}
|
||||
|
||||
function removeItem(key, callback) {
|
||||
var self = this;
|
||||
|
||||
key = normalizeKey(key);
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.db.transaction(function(t) {
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`DELETE FROM ${dbInfo.storeName} WHERE key = ?`,
|
||||
[key],
|
||||
function() {
|
||||
resolve();
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Deletes every item in the table.
|
||||
// TODO: Find out if this resets the AUTO_INCREMENT number.
|
||||
function clear(callback) {
|
||||
var self = this;
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.db.transaction(function(t) {
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`DELETE FROM ${dbInfo.storeName}`,
|
||||
[],
|
||||
function() {
|
||||
resolve();
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Does a simple `COUNT(key)` to get the number of items stored in
|
||||
// localForage.
|
||||
function length(callback) {
|
||||
var self = this;
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.db.transaction(function(t) {
|
||||
// Ahhh, SQL makes this one soooooo easy.
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`SELECT COUNT(key) as c FROM ${dbInfo.storeName}`,
|
||||
[],
|
||||
function(t, results) {
|
||||
var result = results.rows.item(0).c;
|
||||
resolve(result);
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// Return the key located at key index X; essentially gets the key from a
|
||||
// `WHERE id = ?`. This is the most efficient way I can think to implement
|
||||
// this rarely-used (in my experience) part of the API, but it can seem
|
||||
// inconsistent, because we do `INSERT OR REPLACE INTO` on `setItem()`, so
|
||||
// the ID of each key will change every time it's updated. Perhaps a stored
|
||||
// procedure for the `setItem()` SQL would solve this problem?
|
||||
// TODO: Don't change ID on `setItem()`.
|
||||
function key(n, callback) {
|
||||
var self = this;
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.db.transaction(function(t) {
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`SELECT key FROM ${
|
||||
dbInfo.storeName
|
||||
} WHERE id = ? LIMIT 1`,
|
||||
[n + 1],
|
||||
function(t, results) {
|
||||
var result = results.rows.length
|
||||
? results.rows.item(0).key
|
||||
: null;
|
||||
resolve(result);
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
function keys(callback) {
|
||||
var self = this;
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
self
|
||||
.ready()
|
||||
.then(function() {
|
||||
var dbInfo = self._dbInfo;
|
||||
dbInfo.db.transaction(function(t) {
|
||||
tryExecuteSql(
|
||||
t,
|
||||
dbInfo,
|
||||
`SELECT key FROM ${dbInfo.storeName}`,
|
||||
[],
|
||||
function(t, results) {
|
||||
var keys = [];
|
||||
|
||||
for (var i = 0; i < results.rows.length; i++) {
|
||||
keys.push(results.rows.item(i).key);
|
||||
}
|
||||
|
||||
resolve(keys);
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/webdatabase/#databases
|
||||
// > There is no way to enumerate or delete the databases available for an origin from this API.
|
||||
function getAllStoreNames(db) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
db.transaction(
|
||||
function(t) {
|
||||
t.executeSql(
|
||||
'SELECT name FROM sqlite_master ' +
|
||||
"WHERE type='table' AND name <> '__WebKitDatabaseInfoTable__'",
|
||||
[],
|
||||
function(t, results) {
|
||||
var storeNames = [];
|
||||
|
||||
for (var i = 0; i < results.rows.length; i++) {
|
||||
storeNames.push(results.rows.item(i).name);
|
||||
}
|
||||
|
||||
resolve({
|
||||
db,
|
||||
storeNames
|
||||
});
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
},
|
||||
function(sqlError) {
|
||||
reject(sqlError);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function dropInstance(options, callback) {
|
||||
callback = getCallback.apply(this, arguments);
|
||||
|
||||
var currentConfig = this.config();
|
||||
options = (typeof options !== 'function' && options) || {};
|
||||
if (!options.name) {
|
||||
options.name = options.name || currentConfig.name;
|
||||
options.storeName = options.storeName || currentConfig.storeName;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var promise;
|
||||
if (!options.name) {
|
||||
promise = Promise.reject('Invalid arguments');
|
||||
} else {
|
||||
promise = new Promise(function(resolve) {
|
||||
var db;
|
||||
if (options.name === currentConfig.name) {
|
||||
// use the db reference of the current instance
|
||||
db = self._dbInfo.db;
|
||||
} else {
|
||||
db = openDatabase(options.name, '', '', 0);
|
||||
}
|
||||
|
||||
if (!options.storeName) {
|
||||
// drop all database tables
|
||||
resolve(getAllStoreNames(db));
|
||||
} else {
|
||||
resolve({
|
||||
db,
|
||||
storeNames: [options.storeName]
|
||||
});
|
||||
}
|
||||
}).then(function(operationInfo) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
operationInfo.db.transaction(
|
||||
function(t) {
|
||||
function dropTable(storeName) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
t.executeSql(
|
||||
`DROP TABLE IF EXISTS ${storeName}`,
|
||||
[],
|
||||
function() {
|
||||
resolve();
|
||||
},
|
||||
function(t, error) {
|
||||
reject(error);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
var operations = [];
|
||||
for (
|
||||
var i = 0, len = operationInfo.storeNames.length;
|
||||
i < len;
|
||||
i++
|
||||
) {
|
||||
operations.push(
|
||||
dropTable(operationInfo.storeNames[i])
|
||||
);
|
||||
}
|
||||
|
||||
Promise.all(operations)
|
||||
.then(function() {
|
||||
resolve();
|
||||
})
|
||||
.catch(function(e) {
|
||||
reject(e);
|
||||
});
|
||||
},
|
||||
function(sqlError) {
|
||||
reject(sqlError);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
executeCallback(promise, callback);
|
||||
return promise;
|
||||
}
|
||||
|
||||
var webSQLStorage = {
|
||||
_driver: 'webSQLStorage',
|
||||
_initStorage: _initStorage,
|
||||
_support: isWebSQLValid(),
|
||||
iterate: iterate,
|
||||
getItem: getItem,
|
||||
setItem: setItem,
|
||||
removeItem: removeItem,
|
||||
clear: clear,
|
||||
length: length,
|
||||
key: key,
|
||||
keys: keys,
|
||||
dropInstance: dropInstance
|
||||
};
|
||||
|
||||
export default webSQLStorage;
|
||||
Reference in New Issue
Block a user