localforage.nopromises.js 78 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173
  1. /*!
  2. localForage -- Offline Storage, Improved
  3. Version 1.4.0
  4. https://mozilla.github.io/localForage
  5. (c) 2013-2015 Mozilla, Apache License 2.0
  6. */
  7. (function webpackUniversalModuleDefinition(root, factory) {
  8. if(typeof exports === 'object' && typeof module === 'object')
  9. module.exports = factory();
  10. else if(typeof define === 'function' && define.amd)
  11. define([], factory);
  12. else if(typeof exports === 'object')
  13. exports["localforage"] = factory();
  14. else
  15. root["localforage"] = factory();
  16. })(this, function() {
  17. return /******/ (function(modules) { // webpackBootstrap
  18. /******/ // The module cache
  19. /******/ var installedModules = {};
  20. /******/ // The require function
  21. /******/ function __webpack_require__(moduleId) {
  22. /******/ // Check if module is in cache
  23. /******/ if(installedModules[moduleId])
  24. /******/ return installedModules[moduleId].exports;
  25. /******/ // Create a new module (and put it into the cache)
  26. /******/ var module = installedModules[moduleId] = {
  27. /******/ exports: {},
  28. /******/ id: moduleId,
  29. /******/ loaded: false
  30. /******/ };
  31. /******/ // Execute the module function
  32. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  33. /******/ // Flag the module as loaded
  34. /******/ module.loaded = true;
  35. /******/ // Return the exports of the module
  36. /******/ return module.exports;
  37. /******/ }
  38. /******/ // expose the modules object (__webpack_modules__)
  39. /******/ __webpack_require__.m = modules;
  40. /******/ // expose the module cache
  41. /******/ __webpack_require__.c = installedModules;
  42. /******/ // __webpack_public_path__
  43. /******/ __webpack_require__.p = "";
  44. /******/ // Load entry module and return exports
  45. /******/ return __webpack_require__(0);
  46. /******/ })
  47. /************************************************************************/
  48. /******/ ([
  49. /* 0 */
  50. /***/ function(module, exports, __webpack_require__) {
  51. 'use strict';
  52. exports.__esModule = true;
  53. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
  54. var localForage = (function (globalObject) {
  55. 'use strict';
  56. // Custom drivers are stored here when `defineDriver()` is called.
  57. // They are shared across all instances of localForage.
  58. var CustomDrivers = {};
  59. var DriverType = {
  60. INDEXEDDB: 'asyncStorage',
  61. LOCALSTORAGE: 'localStorageWrapper',
  62. WEBSQL: 'webSQLStorage'
  63. };
  64. var DefaultDriverOrder = [DriverType.INDEXEDDB, DriverType.WEBSQL, DriverType.LOCALSTORAGE];
  65. var LibraryMethods = ['clear', 'getItem', 'iterate', 'key', 'keys', 'length', 'removeItem', 'setItem'];
  66. var DefaultConfig = {
  67. description: '',
  68. driver: DefaultDriverOrder.slice(),
  69. name: 'localforage',
  70. // Default DB size is _JUST UNDER_ 5MB, as it's the highest size
  71. // we can use without a prompt.
  72. size: 4980736,
  73. storeName: 'keyvaluepairs',
  74. version: 1.0
  75. };
  76. var driverSupport = (function (self) {
  77. var result = {};
  78. // Check to see if IndexedDB is available and if it is the latest
  79. // implementation; it's our preferred backend library. We use "_spec_test"
  80. // as the name of the database because it's not the one we'll operate on,
  81. // but it's useful to make sure its using the right spec.
  82. // See: https://github.com/mozilla/localForage/issues/128
  83. result[DriverType.INDEXEDDB] = !!(function () {
  84. try {
  85. // Initialize IndexedDB; fall back to vendor-prefixed versions
  86. // if needed.
  87. var indexedDB = indexedDB || self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.OIndexedDB || self.msIndexedDB;
  88. // We mimic PouchDB here; just UA test for Safari (which, as of
  89. // iOS 8/Yosemite, doesn't properly support IndexedDB).
  90. // IndexedDB support is broken and different from Blink's.
  91. // This is faster than the test case (and it's sync), so we just
  92. // do this. *SIGH*
  93. // http://bl.ocks.org/nolanlawson/raw/c83e9039edf2278047e9/
  94. //
  95. // We test for openDatabase because IE Mobile identifies itself
  96. // as Safari. Oh the lulz...
  97. if (typeof self.openDatabase !== 'undefined' && self.navigator && self.navigator.userAgent && /Safari/.test(self.navigator.userAgent) && !/Chrome/.test(self.navigator.userAgent)) {
  98. return false;
  99. }
  100. return indexedDB && typeof indexedDB.open === 'function' &&
  101. // Some Samsung/HTC Android 4.0-4.3 devices
  102. // have older IndexedDB specs; if this isn't available
  103. // their IndexedDB is too old for us to use.
  104. // (Replaces the onupgradeneeded test.)
  105. typeof self.IDBKeyRange !== 'undefined';
  106. } catch (e) {
  107. return false;
  108. }
  109. })();
  110. result[DriverType.WEBSQL] = !!(function () {
  111. try {
  112. return self.openDatabase;
  113. } catch (e) {
  114. return false;
  115. }
  116. })();
  117. result[DriverType.LOCALSTORAGE] = !!(function () {
  118. try {
  119. return self.localStorage && 'setItem' in self.localStorage && self.localStorage.setItem;
  120. } catch (e) {
  121. return false;
  122. }
  123. })();
  124. return result;
  125. })(globalObject);
  126. var isArray = Array.isArray || function (arg) {
  127. return Object.prototype.toString.call(arg) === '[object Array]';
  128. };
  129. function callWhenReady(localForageInstance, libraryMethod) {
  130. localForageInstance[libraryMethod] = function () {
  131. var _args = arguments;
  132. return localForageInstance.ready().then(function () {
  133. return localForageInstance[libraryMethod].apply(localForageInstance, _args);
  134. });
  135. };
  136. }
  137. function extend() {
  138. for (var i = 1; i < arguments.length; i++) {
  139. var arg = arguments[i];
  140. if (arg) {
  141. for (var key in arg) {
  142. if (arg.hasOwnProperty(key)) {
  143. if (isArray(arg[key])) {
  144. arguments[0][key] = arg[key].slice();
  145. } else {
  146. arguments[0][key] = arg[key];
  147. }
  148. }
  149. }
  150. }
  151. }
  152. return arguments[0];
  153. }
  154. function isLibraryDriver(driverName) {
  155. for (var driver in DriverType) {
  156. if (DriverType.hasOwnProperty(driver) && DriverType[driver] === driverName) {
  157. return true;
  158. }
  159. }
  160. return false;
  161. }
  162. var LocalForage = (function () {
  163. function LocalForage(options) {
  164. _classCallCheck(this, LocalForage);
  165. this.INDEXEDDB = DriverType.INDEXEDDB;
  166. this.LOCALSTORAGE = DriverType.LOCALSTORAGE;
  167. this.WEBSQL = DriverType.WEBSQL;
  168. this._defaultConfig = extend({}, DefaultConfig);
  169. this._config = extend({}, this._defaultConfig, options);
  170. this._driverSet = null;
  171. this._initDriver = null;
  172. this._ready = false;
  173. this._dbInfo = null;
  174. this._wrapLibraryMethodsWithReady();
  175. this.setDriver(this._config.driver);
  176. }
  177. // The actual localForage object that we expose as a module or via a
  178. // global. It's extended by pulling in one of our other libraries.
  179. // Set any config values for localForage; can be called anytime before
  180. // the first API call (e.g. `getItem`, `setItem`).
  181. // We loop through options so we don't overwrite existing config
  182. // values.
  183. LocalForage.prototype.config = function config(options) {
  184. // If the options argument is an object, we use it to set values.
  185. // Otherwise, we return either a specified config value or all
  186. // config values.
  187. if (typeof options === 'object') {
  188. // If localforage is ready and fully initialized, we can't set
  189. // any new configuration values. Instead, we return an error.
  190. if (this._ready) {
  191. return new Error("Can't call config() after localforage " + 'has been used.');
  192. }
  193. for (var i in options) {
  194. if (i === 'storeName') {
  195. options[i] = options[i].replace(/\W/g, '_');
  196. }
  197. this._config[i] = options[i];
  198. }
  199. // after all config options are set and
  200. // the driver option is used, try setting it
  201. if ('driver' in options && options.driver) {
  202. this.setDriver(this._config.driver);
  203. }
  204. return true;
  205. } else if (typeof options === 'string') {
  206. return this._config[options];
  207. } else {
  208. return this._config;
  209. }
  210. };
  211. // Used to define a custom driver, shared across all instances of
  212. // localForage.
  213. LocalForage.prototype.defineDriver = function defineDriver(driverObject, callback, errorCallback) {
  214. var promise = new Promise(function (resolve, reject) {
  215. try {
  216. var driverName = driverObject._driver;
  217. var complianceError = new Error('Custom driver not compliant; see ' + 'https://mozilla.github.io/localForage/#definedriver');
  218. var namingError = new Error('Custom driver name already in use: ' + driverObject._driver);
  219. // A driver name should be defined and not overlap with the
  220. // library-defined, default drivers.
  221. if (!driverObject._driver) {
  222. reject(complianceError);
  223. return;
  224. }
  225. if (isLibraryDriver(driverObject._driver)) {
  226. reject(namingError);
  227. return;
  228. }
  229. var customDriverMethods = LibraryMethods.concat('_initStorage');
  230. for (var i = 0; i < customDriverMethods.length; i++) {
  231. var customDriverMethod = customDriverMethods[i];
  232. if (!customDriverMethod || !driverObject[customDriverMethod] || typeof driverObject[customDriverMethod] !== 'function') {
  233. reject(complianceError);
  234. return;
  235. }
  236. }
  237. var supportPromise = Promise.resolve(true);
  238. if ('_support' in driverObject) {
  239. if (driverObject._support && typeof driverObject._support === 'function') {
  240. supportPromise = driverObject._support();
  241. } else {
  242. supportPromise = Promise.resolve(!!driverObject._support);
  243. }
  244. }
  245. supportPromise.then(function (supportResult) {
  246. driverSupport[driverName] = supportResult;
  247. CustomDrivers[driverName] = driverObject;
  248. resolve();
  249. }, reject);
  250. } catch (e) {
  251. reject(e);
  252. }
  253. });
  254. promise.then(callback, errorCallback);
  255. return promise;
  256. };
  257. LocalForage.prototype.driver = function driver() {
  258. return this._driver || null;
  259. };
  260. LocalForage.prototype.getDriver = function getDriver(driverName, callback, errorCallback) {
  261. var self = this;
  262. var getDriverPromise = (function () {
  263. if (isLibraryDriver(driverName)) {
  264. switch (driverName) {
  265. case self.INDEXEDDB:
  266. return new Promise(function (resolve, reject) {
  267. resolve(__webpack_require__(1));
  268. });
  269. case self.LOCALSTORAGE:
  270. return new Promise(function (resolve, reject) {
  271. resolve(__webpack_require__(2));
  272. });
  273. case self.WEBSQL:
  274. return new Promise(function (resolve, reject) {
  275. resolve(__webpack_require__(4));
  276. });
  277. }
  278. } else if (CustomDrivers[driverName]) {
  279. return Promise.resolve(CustomDrivers[driverName]);
  280. }
  281. return Promise.reject(new Error('Driver not found.'));
  282. })();
  283. getDriverPromise.then(callback, errorCallback);
  284. return getDriverPromise;
  285. };
  286. LocalForage.prototype.getSerializer = function getSerializer(callback) {
  287. var serializerPromise = new Promise(function (resolve, reject) {
  288. resolve(__webpack_require__(3));
  289. });
  290. if (callback && typeof callback === 'function') {
  291. serializerPromise.then(function (result) {
  292. callback(result);
  293. });
  294. }
  295. return serializerPromise;
  296. };
  297. LocalForage.prototype.ready = function ready(callback) {
  298. var self = this;
  299. var promise = self._driverSet.then(function () {
  300. if (self._ready === null) {
  301. self._ready = self._initDriver();
  302. }
  303. return self._ready;
  304. });
  305. promise.then(callback, callback);
  306. return promise;
  307. };
  308. LocalForage.prototype.setDriver = function setDriver(drivers, callback, errorCallback) {
  309. var self = this;
  310. if (!isArray(drivers)) {
  311. drivers = [drivers];
  312. }
  313. var supportedDrivers = this._getSupportedDrivers(drivers);
  314. function setDriverToConfig() {
  315. self._config.driver = self.driver();
  316. }
  317. function initDriver(supportedDrivers) {
  318. return function () {
  319. var currentDriverIndex = 0;
  320. function driverPromiseLoop() {
  321. while (currentDriverIndex < supportedDrivers.length) {
  322. var driverName = supportedDrivers[currentDriverIndex];
  323. currentDriverIndex++;
  324. self._dbInfo = null;
  325. self._ready = null;
  326. return self.getDriver(driverName).then(function (driver) {
  327. self._extend(driver);
  328. setDriverToConfig();
  329. self._ready = self._initStorage(self._config);
  330. return self._ready;
  331. })['catch'](driverPromiseLoop);
  332. }
  333. setDriverToConfig();
  334. var error = new Error('No available storage method found.');
  335. self._driverSet = Promise.reject(error);
  336. return self._driverSet;
  337. }
  338. return driverPromiseLoop();
  339. };
  340. }
  341. // There might be a driver initialization in progress
  342. // so wait for it to finish in order to avoid a possible
  343. // race condition to set _dbInfo
  344. var oldDriverSetDone = this._driverSet !== null ? this._driverSet['catch'](function () {
  345. return Promise.resolve();
  346. }) : Promise.resolve();
  347. this._driverSet = oldDriverSetDone.then(function () {
  348. var driverName = supportedDrivers[0];
  349. self._dbInfo = null;
  350. self._ready = null;
  351. return self.getDriver(driverName).then(function (driver) {
  352. self._driver = driver._driver;
  353. setDriverToConfig();
  354. self._wrapLibraryMethodsWithReady();
  355. self._initDriver = initDriver(supportedDrivers);
  356. });
  357. })['catch'](function () {
  358. setDriverToConfig();
  359. var error = new Error('No available storage method found.');
  360. self._driverSet = Promise.reject(error);
  361. return self._driverSet;
  362. });
  363. this._driverSet.then(callback, errorCallback);
  364. return this._driverSet;
  365. };
  366. LocalForage.prototype.supports = function supports(driverName) {
  367. return !!driverSupport[driverName];
  368. };
  369. LocalForage.prototype._extend = function _extend(libraryMethodsAndProperties) {
  370. extend(this, libraryMethodsAndProperties);
  371. };
  372. LocalForage.prototype._getSupportedDrivers = function _getSupportedDrivers(drivers) {
  373. var supportedDrivers = [];
  374. for (var i = 0, len = drivers.length; i < len; i++) {
  375. var driverName = drivers[i];
  376. if (this.supports(driverName)) {
  377. supportedDrivers.push(driverName);
  378. }
  379. }
  380. return supportedDrivers;
  381. };
  382. LocalForage.prototype._wrapLibraryMethodsWithReady = function _wrapLibraryMethodsWithReady() {
  383. // Add a stub for each driver API method that delays the call to the
  384. // corresponding driver method until localForage is ready. These stubs
  385. // will be replaced by the driver methods as soon as the driver is
  386. // loaded, so there is no performance impact.
  387. for (var i = 0; i < LibraryMethods.length; i++) {
  388. callWhenReady(this, LibraryMethods[i]);
  389. }
  390. };
  391. LocalForage.prototype.createInstance = function createInstance(options) {
  392. return new LocalForage(options);
  393. };
  394. return LocalForage;
  395. })();
  396. return new LocalForage();
  397. })(typeof window !== 'undefined' ? window : self);
  398. exports['default'] = localForage;
  399. module.exports = exports['default'];
  400. /***/ },
  401. /* 1 */
  402. /***/ function(module, exports) {
  403. // Some code originally from async_storage.js in
  404. // [Gaia](https://github.com/mozilla-b2g/gaia).
  405. 'use strict';
  406. exports.__esModule = true;
  407. var asyncStorage = (function (globalObject) {
  408. 'use strict';
  409. // Initialize IndexedDB; fall back to vendor-prefixed versions if needed.
  410. var indexedDB = indexedDB || globalObject.indexedDB || globalObject.webkitIndexedDB || globalObject.mozIndexedDB || globalObject.OIndexedDB || globalObject.msIndexedDB;
  411. // If IndexedDB isn't available, we get outta here!
  412. if (!indexedDB) {
  413. return;
  414. }
  415. var DETECT_BLOB_SUPPORT_STORE = 'local-forage-detect-blob-support';
  416. var supportsBlobs;
  417. var dbContexts;
  418. // Abstracts constructing a Blob object, so it also works in older
  419. // browsers that don't support the native Blob constructor. (i.e.
  420. // old QtWebKit versions, at least).
  421. function _createBlob(parts, properties) {
  422. parts = parts || [];
  423. properties = properties || {};
  424. try {
  425. return new Blob(parts, properties);
  426. } catch (e) {
  427. if (e.name !== 'TypeError') {
  428. throw e;
  429. }
  430. var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;
  431. var builder = new BlobBuilder();
  432. for (var i = 0; i < parts.length; i += 1) {
  433. builder.append(parts[i]);
  434. }
  435. return builder.getBlob(properties.type);
  436. }
  437. }
  438. // Transform a binary string to an array buffer, because otherwise
  439. // weird stuff happens when you try to work with the binary string directly.
  440. // It is known.
  441. // From http://stackoverflow.com/questions/14967647/ (continues on next line)
  442. // encode-decode-image-with-base64-breaks-image (2013-04-21)
  443. function _binStringToArrayBuffer(bin) {
  444. var length = bin.length;
  445. var buf = new ArrayBuffer(length);
  446. var arr = new Uint8Array(buf);
  447. for (var i = 0; i < length; i++) {
  448. arr[i] = bin.charCodeAt(i);
  449. }
  450. return buf;
  451. }
  452. // Fetch a blob using ajax. This reveals bugs in Chrome < 43.
  453. // For details on all this junk:
  454. // https://github.com/nolanlawson/state-of-binary-data-in-the-browser#readme
  455. function _blobAjax(url) {
  456. return new Promise(function (resolve, reject) {
  457. var xhr = new XMLHttpRequest();
  458. xhr.open('GET', url);
  459. xhr.withCredentials = true;
  460. xhr.responseType = 'arraybuffer';
  461. xhr.onreadystatechange = function () {
  462. if (xhr.readyState !== 4) {
  463. return;
  464. }
  465. if (xhr.status === 200) {
  466. return resolve({
  467. response: xhr.response,
  468. type: xhr.getResponseHeader('Content-Type')
  469. });
  470. }
  471. reject({ status: xhr.status, response: xhr.response });
  472. };
  473. xhr.send();
  474. });
  475. }
  476. //
  477. // Detect blob support. Chrome didn't support it until version 38.
  478. // In version 37 they had a broken version where PNGs (and possibly
  479. // other binary types) aren't stored correctly, because when you fetch
  480. // them, the content type is always null.
  481. //
  482. // Furthermore, they have some outstanding bugs where blobs occasionally
  483. // are read by FileReader as null, or by ajax as 404s.
  484. //
  485. // Sadly we use the 404 bug to detect the FileReader bug, so if they
  486. // get fixed independently and released in different versions of Chrome,
  487. // then the bug could come back. So it's worthwhile to watch these issues:
  488. // 404 bug: https://code.google.com/p/chromium/issues/detail?id=447916
  489. // FileReader bug: https://code.google.com/p/chromium/issues/detail?id=447836
  490. //
  491. function _checkBlobSupportWithoutCaching(idb) {
  492. return new Promise(function (resolve, reject) {
  493. var blob = _createBlob([''], { type: 'image/png' });
  494. var txn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');
  495. txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key');
  496. txn.oncomplete = function () {
  497. // have to do it in a separate transaction, else the correct
  498. // content type is always returned
  499. var blobTxn = idb.transaction([DETECT_BLOB_SUPPORT_STORE], 'readwrite');
  500. var getBlobReq = blobTxn.objectStore(DETECT_BLOB_SUPPORT_STORE).get('key');
  501. getBlobReq.onerror = reject;
  502. getBlobReq.onsuccess = function (e) {
  503. var storedBlob = e.target.result;
  504. var url = URL.createObjectURL(storedBlob);
  505. _blobAjax(url).then(function (res) {
  506. resolve(!!(res && res.type === 'image/png'));
  507. }, function () {
  508. resolve(false);
  509. }).then(function () {
  510. URL.revokeObjectURL(url);
  511. });
  512. };
  513. };
  514. txn.onerror = txn.onabort = reject;
  515. })['catch'](function () {
  516. return false; // error, so assume unsupported
  517. });
  518. }
  519. function _checkBlobSupport(idb) {
  520. if (typeof supportsBlobs === 'boolean') {
  521. return Promise.resolve(supportsBlobs);
  522. }
  523. return _checkBlobSupportWithoutCaching(idb).then(function (value) {
  524. supportsBlobs = value;
  525. return supportsBlobs;
  526. });
  527. }
  528. // encode a blob for indexeddb engines that don't support blobs
  529. function _encodeBlob(blob) {
  530. return new Promise(function (resolve, reject) {
  531. var reader = new FileReader();
  532. reader.onerror = reject;
  533. reader.onloadend = function (e) {
  534. var base64 = btoa(e.target.result || '');
  535. resolve({
  536. __local_forage_encoded_blob: true,
  537. data: base64,
  538. type: blob.type
  539. });
  540. };
  541. reader.readAsBinaryString(blob);
  542. });
  543. }
  544. // decode an encoded blob
  545. function _decodeBlob(encodedBlob) {
  546. var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));
  547. return _createBlob([arrayBuff], { type: encodedBlob.type });
  548. }
  549. // is this one of our fancy encoded blobs?
  550. function _isEncodedBlob(value) {
  551. return value && value.__local_forage_encoded_blob;
  552. }
  553. // Specialize the default `ready()` function by making it dependent
  554. // on the current database operations. Thus, the driver will be actually
  555. // ready when it's been initialized (default) *and* there are no pending
  556. // operations on the database (initiated by some other instances).
  557. function _fullyReady(callback) {
  558. var self = this;
  559. var promise = self._initReady().then(function () {
  560. var dbContext = dbContexts[self._dbInfo.name];
  561. if (dbContext && dbContext.dbReady) {
  562. return dbContext.dbReady;
  563. }
  564. });
  565. promise.then(callback, callback);
  566. return promise;
  567. }
  568. function _deferReadiness(dbInfo) {
  569. var dbContext = dbContexts[dbInfo.name];
  570. // Create a deferred object representing the current database operation.
  571. var deferredOperation = {};
  572. deferredOperation.promise = new Promise(function (resolve) {
  573. deferredOperation.resolve = resolve;
  574. });
  575. // Enqueue the deferred operation.
  576. dbContext.deferredOperations.push(deferredOperation);
  577. // Chain its promise to the database readiness.
  578. if (!dbContext.dbReady) {
  579. dbContext.dbReady = deferredOperation.promise;
  580. } else {
  581. dbContext.dbReady = dbContext.dbReady.then(function () {
  582. return deferredOperation.promise;
  583. });
  584. }
  585. }
  586. function _advanceReadiness(dbInfo) {
  587. var dbContext = dbContexts[dbInfo.name];
  588. // Dequeue a deferred operation.
  589. var deferredOperation = dbContext.deferredOperations.pop();
  590. // Resolve its promise (which is part of the database readiness
  591. // chain of promises).
  592. if (deferredOperation) {
  593. deferredOperation.resolve();
  594. }
  595. }
  596. // Open the IndexedDB database (automatically creates one if one didn't
  597. // previously exist), using any options set in the config.
  598. function _initStorage(options) {
  599. var self = this;
  600. var dbInfo = {
  601. db: null
  602. };
  603. if (options) {
  604. for (var i in options) {
  605. dbInfo[i] = options[i];
  606. }
  607. }
  608. // Initialize a singleton container for all running localForages.
  609. if (!dbContexts) {
  610. dbContexts = {};
  611. }
  612. // Get the current context of the database;
  613. var dbContext = dbContexts[dbInfo.name];
  614. // ...or create a new context.
  615. if (!dbContext) {
  616. dbContext = {
  617. // Running localForages sharing a database.
  618. forages: [],
  619. // Shared database.
  620. db: null,
  621. // Database readiness (promise).
  622. dbReady: null,
  623. // Deferred operations on the database.
  624. deferredOperations: []
  625. };
  626. // Register the new context in the global container.
  627. dbContexts[dbInfo.name] = dbContext;
  628. }
  629. // Register itself as a running localForage in the current context.
  630. dbContext.forages.push(self);
  631. // Replace the default `ready()` function with the specialized one.
  632. if (!self._initReady) {
  633. self._initReady = self.ready;
  634. self.ready = _fullyReady;
  635. }
  636. // Create an array of initialization states of the related localForages.
  637. var initPromises = [];
  638. function ignoreErrors() {
  639. // Don't handle errors here,
  640. // just makes sure related localForages aren't pending.
  641. return Promise.resolve();
  642. }
  643. for (var j = 0; j < dbContext.forages.length; j++) {
  644. var forage = dbContext.forages[j];
  645. if (forage !== self) {
  646. // Don't wait for itself...
  647. initPromises.push(forage._initReady()['catch'](ignoreErrors));
  648. }
  649. }
  650. // Take a snapshot of the related localForages.
  651. var forages = dbContext.forages.slice(0);
  652. // Initialize the connection process only when
  653. // all the related localForages aren't pending.
  654. return Promise.all(initPromises).then(function () {
  655. dbInfo.db = dbContext.db;
  656. // Get the connection or open a new one without upgrade.
  657. return _getOriginalConnection(dbInfo);
  658. }).then(function (db) {
  659. dbInfo.db = db;
  660. if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) {
  661. // Reopen the database for upgrading.
  662. return _getUpgradedConnection(dbInfo);
  663. }
  664. return db;
  665. }).then(function (db) {
  666. dbInfo.db = dbContext.db = db;
  667. self._dbInfo = dbInfo;
  668. // Share the final connection amongst related localForages.
  669. for (var k = 0; k < forages.length; k++) {
  670. var forage = forages[k];
  671. if (forage !== self) {
  672. // Self is already up-to-date.
  673. forage._dbInfo.db = dbInfo.db;
  674. forage._dbInfo.version = dbInfo.version;
  675. }
  676. }
  677. });
  678. }
  679. function _getOriginalConnection(dbInfo) {
  680. return _getConnection(dbInfo, false);
  681. }
  682. function _getUpgradedConnection(dbInfo) {
  683. return _getConnection(dbInfo, true);
  684. }
  685. function _getConnection(dbInfo, upgradeNeeded) {
  686. return new Promise(function (resolve, reject) {
  687. if (dbInfo.db) {
  688. if (upgradeNeeded) {
  689. _deferReadiness(dbInfo);
  690. dbInfo.db.close();
  691. } else {
  692. return resolve(dbInfo.db);
  693. }
  694. }
  695. var dbArgs = [dbInfo.name];
  696. if (upgradeNeeded) {
  697. dbArgs.push(dbInfo.version);
  698. }
  699. var openreq = indexedDB.open.apply(indexedDB, dbArgs);
  700. if (upgradeNeeded) {
  701. openreq.onupgradeneeded = function (e) {
  702. var db = openreq.result;
  703. try {
  704. db.createObjectStore(dbInfo.storeName);
  705. if (e.oldVersion <= 1) {
  706. // Added when support for blob shims was added
  707. db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);
  708. }
  709. } catch (ex) {
  710. if (ex.name === 'ConstraintError') {
  711. globalObject.console.warn('The database "' + dbInfo.name + '"' + ' has been upgraded from version ' + e.oldVersion + ' to version ' + e.newVersion + ', but the storage "' + dbInfo.storeName + '" already exists.');
  712. } else {
  713. throw ex;
  714. }
  715. }
  716. };
  717. }
  718. openreq.onerror = function () {
  719. reject(openreq.error);
  720. };
  721. openreq.onsuccess = function () {
  722. resolve(openreq.result);
  723. _advanceReadiness(dbInfo);
  724. };
  725. });
  726. }
  727. function _isUpgradeNeeded(dbInfo, defaultVersion) {
  728. if (!dbInfo.db) {
  729. return true;
  730. }
  731. var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);
  732. var isDowngrade = dbInfo.version < dbInfo.db.version;
  733. var isUpgrade = dbInfo.version > dbInfo.db.version;
  734. if (isDowngrade) {
  735. // If the version is not the default one
  736. // then warn for impossible downgrade.
  737. if (dbInfo.version !== defaultVersion) {
  738. globalObject.console.warn('The database "' + dbInfo.name + '"' + ' can\'t be downgraded from version ' + dbInfo.db.version + ' to version ' + dbInfo.version + '.');
  739. }
  740. // Align the versions to prevent errors.
  741. dbInfo.version = dbInfo.db.version;
  742. }
  743. if (isUpgrade || isNewStore) {
  744. // If the store is new then increment the version (if needed).
  745. // This will trigger an "upgradeneeded" event which is required
  746. // for creating a store.
  747. if (isNewStore) {
  748. var incVersion = dbInfo.db.version + 1;
  749. if (incVersion > dbInfo.version) {
  750. dbInfo.version = incVersion;
  751. }
  752. }
  753. return true;
  754. }
  755. return false;
  756. }
  757. function getItem(key, callback) {
  758. var self = this;
  759. // Cast the key to a string, as that's all we can set as a key.
  760. if (typeof key !== 'string') {
  761. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  762. key = String(key);
  763. }
  764. var promise = new Promise(function (resolve, reject) {
  765. self.ready().then(function () {
  766. var dbInfo = self._dbInfo;
  767. var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);
  768. var req = store.get(key);
  769. req.onsuccess = function () {
  770. var value = req.result;
  771. if (value === undefined) {
  772. value = null;
  773. }
  774. if (_isEncodedBlob(value)) {
  775. value = _decodeBlob(value);
  776. }
  777. resolve(value);
  778. };
  779. req.onerror = function () {
  780. reject(req.error);
  781. };
  782. })['catch'](reject);
  783. });
  784. executeCallback(promise, callback);
  785. return promise;
  786. }
  787. // Iterate over all items stored in database.
  788. function iterate(iterator, callback) {
  789. var self = this;
  790. var promise = new Promise(function (resolve, reject) {
  791. self.ready().then(function () {
  792. var dbInfo = self._dbInfo;
  793. var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);
  794. var req = store.openCursor();
  795. var iterationNumber = 1;
  796. req.onsuccess = function () {
  797. var cursor = req.result;
  798. if (cursor) {
  799. var value = cursor.value;
  800. if (_isEncodedBlob(value)) {
  801. value = _decodeBlob(value);
  802. }
  803. var result = iterator(value, cursor.key, iterationNumber++);
  804. if (result !== void 0) {
  805. resolve(result);
  806. } else {
  807. cursor['continue']();
  808. }
  809. } else {
  810. resolve();
  811. }
  812. };
  813. req.onerror = function () {
  814. reject(req.error);
  815. };
  816. })['catch'](reject);
  817. });
  818. executeCallback(promise, callback);
  819. return promise;
  820. }
  821. function setItem(key, value, callback) {
  822. var self = this;
  823. // Cast the key to a string, as that's all we can set as a key.
  824. if (typeof key !== 'string') {
  825. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  826. key = String(key);
  827. }
  828. var promise = new Promise(function (resolve, reject) {
  829. var dbInfo;
  830. self.ready().then(function () {
  831. dbInfo = self._dbInfo;
  832. if (value instanceof Blob) {
  833. return _checkBlobSupport(dbInfo.db).then(function (blobSupport) {
  834. if (blobSupport) {
  835. return value;
  836. }
  837. return _encodeBlob(value);
  838. });
  839. }
  840. return value;
  841. }).then(function (value) {
  842. var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
  843. var store = transaction.objectStore(dbInfo.storeName);
  844. // The reason we don't _save_ null is because IE 10 does
  845. // not support saving the `null` type in IndexedDB. How
  846. // ironic, given the bug below!
  847. // See: https://github.com/mozilla/localForage/issues/161
  848. if (value === null) {
  849. value = undefined;
  850. }
  851. transaction.oncomplete = function () {
  852. // Cast to undefined so the value passed to
  853. // callback/promise is the same as what one would get out
  854. // of `getItem()` later. This leads to some weirdness
  855. // (setItem('foo', undefined) will return `null`), but
  856. // it's not my fault localStorage is our baseline and that
  857. // it's weird.
  858. if (value === undefined) {
  859. value = null;
  860. }
  861. resolve(value);
  862. };
  863. transaction.onabort = transaction.onerror = function () {
  864. var err = req.error ? req.error : req.transaction.error;
  865. reject(err);
  866. };
  867. var req = store.put(value, key);
  868. })['catch'](reject);
  869. });
  870. executeCallback(promise, callback);
  871. return promise;
  872. }
  873. function removeItem(key, callback) {
  874. var self = this;
  875. // Cast the key to a string, as that's all we can set as a key.
  876. if (typeof key !== 'string') {
  877. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  878. key = String(key);
  879. }
  880. var promise = new Promise(function (resolve, reject) {
  881. self.ready().then(function () {
  882. var dbInfo = self._dbInfo;
  883. var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
  884. var store = transaction.objectStore(dbInfo.storeName);
  885. // We use a Grunt task to make this safe for IE and some
  886. // versions of Android (including those used by Cordova).
  887. // Normally IE won't like `.delete()` and will insist on
  888. // using `['delete']()`, but we have a build step that
  889. // fixes this for us now.
  890. var req = store['delete'](key);
  891. transaction.oncomplete = function () {
  892. resolve();
  893. };
  894. transaction.onerror = function () {
  895. reject(req.error);
  896. };
  897. // The request will be also be aborted if we've exceeded our storage
  898. // space.
  899. transaction.onabort = function () {
  900. var err = req.error ? req.error : req.transaction.error;
  901. reject(err);
  902. };
  903. })['catch'](reject);
  904. });
  905. executeCallback(promise, callback);
  906. return promise;
  907. }
  908. function clear(callback) {
  909. var self = this;
  910. var promise = new Promise(function (resolve, reject) {
  911. self.ready().then(function () {
  912. var dbInfo = self._dbInfo;
  913. var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
  914. var store = transaction.objectStore(dbInfo.storeName);
  915. var req = store.clear();
  916. transaction.oncomplete = function () {
  917. resolve();
  918. };
  919. transaction.onabort = transaction.onerror = function () {
  920. var err = req.error ? req.error : req.transaction.error;
  921. reject(err);
  922. };
  923. })['catch'](reject);
  924. });
  925. executeCallback(promise, callback);
  926. return promise;
  927. }
  928. function length(callback) {
  929. var self = this;
  930. var promise = new Promise(function (resolve, reject) {
  931. self.ready().then(function () {
  932. var dbInfo = self._dbInfo;
  933. var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);
  934. var req = store.count();
  935. req.onsuccess = function () {
  936. resolve(req.result);
  937. };
  938. req.onerror = function () {
  939. reject(req.error);
  940. };
  941. })['catch'](reject);
  942. });
  943. executeCallback(promise, callback);
  944. return promise;
  945. }
  946. function key(n, callback) {
  947. var self = this;
  948. var promise = new Promise(function (resolve, reject) {
  949. if (n < 0) {
  950. resolve(null);
  951. return;
  952. }
  953. self.ready().then(function () {
  954. var dbInfo = self._dbInfo;
  955. var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);
  956. var advanced = false;
  957. var req = store.openCursor();
  958. req.onsuccess = function () {
  959. var cursor = req.result;
  960. if (!cursor) {
  961. // this means there weren't enough keys
  962. resolve(null);
  963. return;
  964. }
  965. if (n === 0) {
  966. // We have the first key, return it if that's what they
  967. // wanted.
  968. resolve(cursor.key);
  969. } else {
  970. if (!advanced) {
  971. // Otherwise, ask the cursor to skip ahead n
  972. // records.
  973. advanced = true;
  974. cursor.advance(n);
  975. } else {
  976. // When we get here, we've got the nth key.
  977. resolve(cursor.key);
  978. }
  979. }
  980. };
  981. req.onerror = function () {
  982. reject(req.error);
  983. };
  984. })['catch'](reject);
  985. });
  986. executeCallback(promise, callback);
  987. return promise;
  988. }
  989. function keys(callback) {
  990. var self = this;
  991. var promise = new Promise(function (resolve, reject) {
  992. self.ready().then(function () {
  993. var dbInfo = self._dbInfo;
  994. var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly').objectStore(dbInfo.storeName);
  995. var req = store.openCursor();
  996. var keys = [];
  997. req.onsuccess = function () {
  998. var cursor = req.result;
  999. if (!cursor) {
  1000. resolve(keys);
  1001. return;
  1002. }
  1003. keys.push(cursor.key);
  1004. cursor['continue']();
  1005. };
  1006. req.onerror = function () {
  1007. reject(req.error);
  1008. };
  1009. })['catch'](reject);
  1010. });
  1011. executeCallback(promise, callback);
  1012. return promise;
  1013. }
  1014. function executeCallback(promise, callback) {
  1015. if (callback) {
  1016. promise.then(function (result) {
  1017. callback(null, result);
  1018. }, function (error) {
  1019. callback(error);
  1020. });
  1021. }
  1022. }
  1023. var asyncStorage = {
  1024. _driver: 'asyncStorage',
  1025. _initStorage: _initStorage,
  1026. iterate: iterate,
  1027. getItem: getItem,
  1028. setItem: setItem,
  1029. removeItem: removeItem,
  1030. clear: clear,
  1031. length: length,
  1032. key: key,
  1033. keys: keys
  1034. };
  1035. return asyncStorage;
  1036. })(typeof window !== 'undefined' ? window : self);
  1037. exports['default'] = asyncStorage;
  1038. module.exports = exports['default'];
  1039. /***/ },
  1040. /* 2 */
  1041. /***/ function(module, exports, __webpack_require__) {
  1042. // If IndexedDB isn't available, we'll fall back to localStorage.
  1043. // Note that this will have considerable performance and storage
  1044. // side-effects (all data will be serialized on save and only data that
  1045. // can be converted to a string via `JSON.stringify()` will be saved).
  1046. 'use strict';
  1047. exports.__esModule = true;
  1048. var localStorageWrapper = (function (globalObject) {
  1049. 'use strict';
  1050. var localStorage = null;
  1051. // If the app is running inside a Google Chrome packaged webapp, or some
  1052. // other context where localStorage isn't available, we don't use
  1053. // localStorage. This feature detection is preferred over the old
  1054. // `if (window.chrome && window.chrome.runtime)` code.
  1055. // See: https://github.com/mozilla/localForage/issues/68
  1056. try {
  1057. // If localStorage isn't available, we get outta here!
  1058. // This should be inside a try catch
  1059. if (!globalObject.localStorage || !('setItem' in globalObject.localStorage)) {
  1060. return;
  1061. }
  1062. // Initialize localStorage and create a variable to use throughout
  1063. // the code.
  1064. localStorage = globalObject.localStorage;
  1065. } catch (e) {
  1066. return;
  1067. }
  1068. // Config the localStorage backend, using options set in the config.
  1069. function _initStorage(options) {
  1070. var self = this;
  1071. var dbInfo = {};
  1072. if (options) {
  1073. for (var i in options) {
  1074. dbInfo[i] = options[i];
  1075. }
  1076. }
  1077. dbInfo.keyPrefix = dbInfo.name + '/';
  1078. if (dbInfo.storeName !== self._defaultConfig.storeName) {
  1079. dbInfo.keyPrefix += dbInfo.storeName + '/';
  1080. }
  1081. self._dbInfo = dbInfo;
  1082. return new Promise(function (resolve, reject) {
  1083. resolve(__webpack_require__(3));
  1084. }).then(function (lib) {
  1085. dbInfo.serializer = lib;
  1086. return Promise.resolve();
  1087. });
  1088. }
  1089. // Remove all keys from the datastore, effectively destroying all data in
  1090. // the app's key/value store!
  1091. function clear(callback) {
  1092. var self = this;
  1093. var promise = self.ready().then(function () {
  1094. var keyPrefix = self._dbInfo.keyPrefix;
  1095. for (var i = localStorage.length - 1; i >= 0; i--) {
  1096. var key = localStorage.key(i);
  1097. if (key.indexOf(keyPrefix) === 0) {
  1098. localStorage.removeItem(key);
  1099. }
  1100. }
  1101. });
  1102. executeCallback(promise, callback);
  1103. return promise;
  1104. }
  1105. // Retrieve an item from the store. Unlike the original async_storage
  1106. // library in Gaia, we don't modify return values at all. If a key's value
  1107. // is `undefined`, we pass that value to the callback function.
  1108. function getItem(key, callback) {
  1109. var self = this;
  1110. // Cast the key to a string, as that's all we can set as a key.
  1111. if (typeof key !== 'string') {
  1112. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  1113. key = String(key);
  1114. }
  1115. var promise = self.ready().then(function () {
  1116. var dbInfo = self._dbInfo;
  1117. var result = localStorage.getItem(dbInfo.keyPrefix + key);
  1118. // If a result was found, parse it from the serialized
  1119. // string into a JS object. If result isn't truthy, the key
  1120. // is likely undefined and we'll pass it straight to the
  1121. // callback.
  1122. if (result) {
  1123. result = dbInfo.serializer.deserialize(result);
  1124. }
  1125. return result;
  1126. });
  1127. executeCallback(promise, callback);
  1128. return promise;
  1129. }
  1130. // Iterate over all items in the store.
  1131. function iterate(iterator, callback) {
  1132. var self = this;
  1133. var promise = self.ready().then(function () {
  1134. var dbInfo = self._dbInfo;
  1135. var keyPrefix = dbInfo.keyPrefix;
  1136. var keyPrefixLength = keyPrefix.length;
  1137. var length = localStorage.length;
  1138. // We use a dedicated iterator instead of the `i` variable below
  1139. // so other keys we fetch in localStorage aren't counted in
  1140. // the `iterationNumber` argument passed to the `iterate()`
  1141. // callback.
  1142. //
  1143. // See: github.com/mozilla/localForage/pull/435#discussion_r38061530
  1144. var iterationNumber = 1;
  1145. for (var i = 0; i < length; i++) {
  1146. var key = localStorage.key(i);
  1147. if (key.indexOf(keyPrefix) !== 0) {
  1148. continue;
  1149. }
  1150. var value = localStorage.getItem(key);
  1151. // If a result was found, parse it from the serialized
  1152. // string into a JS object. If result isn't truthy, the
  1153. // key is likely undefined and we'll pass it straight
  1154. // to the iterator.
  1155. if (value) {
  1156. value = dbInfo.serializer.deserialize(value);
  1157. }
  1158. value = iterator(value, key.substring(keyPrefixLength), iterationNumber++);
  1159. if (value !== void 0) {
  1160. return value;
  1161. }
  1162. }
  1163. });
  1164. executeCallback(promise, callback);
  1165. return promise;
  1166. }
  1167. // Same as localStorage's key() method, except takes a callback.
  1168. function key(n, callback) {
  1169. var self = this;
  1170. var promise = self.ready().then(function () {
  1171. var dbInfo = self._dbInfo;
  1172. var result;
  1173. try {
  1174. result = localStorage.key(n);
  1175. } catch (error) {
  1176. result = null;
  1177. }
  1178. // Remove the prefix from the key, if a key is found.
  1179. if (result) {
  1180. result = result.substring(dbInfo.keyPrefix.length);
  1181. }
  1182. return result;
  1183. });
  1184. executeCallback(promise, callback);
  1185. return promise;
  1186. }
  1187. function keys(callback) {
  1188. var self = this;
  1189. var promise = self.ready().then(function () {
  1190. var dbInfo = self._dbInfo;
  1191. var length = localStorage.length;
  1192. var keys = [];
  1193. for (var i = 0; i < length; i++) {
  1194. if (localStorage.key(i).indexOf(dbInfo.keyPrefix) === 0) {
  1195. keys.push(localStorage.key(i).substring(dbInfo.keyPrefix.length));
  1196. }
  1197. }
  1198. return keys;
  1199. });
  1200. executeCallback(promise, callback);
  1201. return promise;
  1202. }
  1203. // Supply the number of keys in the datastore to the callback function.
  1204. function length(callback) {
  1205. var self = this;
  1206. var promise = self.keys().then(function (keys) {
  1207. return keys.length;
  1208. });
  1209. executeCallback(promise, callback);
  1210. return promise;
  1211. }
  1212. // Remove an item from the store, nice and simple.
  1213. function removeItem(key, callback) {
  1214. var self = this;
  1215. // Cast the key to a string, as that's all we can set as a key.
  1216. if (typeof key !== 'string') {
  1217. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  1218. key = String(key);
  1219. }
  1220. var promise = self.ready().then(function () {
  1221. var dbInfo = self._dbInfo;
  1222. localStorage.removeItem(dbInfo.keyPrefix + key);
  1223. });
  1224. executeCallback(promise, callback);
  1225. return promise;
  1226. }
  1227. // Set a key's value and run an optional callback once the value is set.
  1228. // Unlike Gaia's implementation, the callback function is passed the value,
  1229. // in case you want to operate on that value only after you're sure it
  1230. // saved, or something like that.
  1231. function setItem(key, value, callback) {
  1232. var self = this;
  1233. // Cast the key to a string, as that's all we can set as a key.
  1234. if (typeof key !== 'string') {
  1235. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  1236. key = String(key);
  1237. }
  1238. var promise = self.ready().then(function () {
  1239. // Convert undefined values to null.
  1240. // https://github.com/mozilla/localForage/pull/42
  1241. if (value === undefined) {
  1242. value = null;
  1243. }
  1244. // Save the original value to pass to the callback.
  1245. var originalValue = value;
  1246. return new Promise(function (resolve, reject) {
  1247. var dbInfo = self._dbInfo;
  1248. dbInfo.serializer.serialize(value, function (value, error) {
  1249. if (error) {
  1250. reject(error);
  1251. } else {
  1252. try {
  1253. localStorage.setItem(dbInfo.keyPrefix + key, value);
  1254. resolve(originalValue);
  1255. } catch (e) {
  1256. // localStorage capacity exceeded.
  1257. // TODO: Make this a specific error/event.
  1258. if (e.name === 'QuotaExceededError' || e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
  1259. reject(e);
  1260. }
  1261. reject(e);
  1262. }
  1263. }
  1264. });
  1265. });
  1266. });
  1267. executeCallback(promise, callback);
  1268. return promise;
  1269. }
  1270. function executeCallback(promise, callback) {
  1271. if (callback) {
  1272. promise.then(function (result) {
  1273. callback(null, result);
  1274. }, function (error) {
  1275. callback(error);
  1276. });
  1277. }
  1278. }
  1279. var localStorageWrapper = {
  1280. _driver: 'localStorageWrapper',
  1281. _initStorage: _initStorage,
  1282. // Default API, from Gaia/localStorage.
  1283. iterate: iterate,
  1284. getItem: getItem,
  1285. setItem: setItem,
  1286. removeItem: removeItem,
  1287. clear: clear,
  1288. length: length,
  1289. key: key,
  1290. keys: keys
  1291. };
  1292. return localStorageWrapper;
  1293. })(typeof window !== 'undefined' ? window : self);
  1294. exports['default'] = localStorageWrapper;
  1295. module.exports = exports['default'];
  1296. /***/ },
  1297. /* 3 */
  1298. /***/ function(module, exports) {
  1299. 'use strict';
  1300. exports.__esModule = true;
  1301. var localforageSerializer = (function (globalObject) {
  1302. 'use strict';
  1303. // Sadly, the best way to save binary data in WebSQL/localStorage is serializing
  1304. // it to Base64, so this is how we store it to prevent very strange errors with less
  1305. // verbose ways of binary <-> string data storage.
  1306. var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  1307. var BLOB_TYPE_PREFIX = '~~local_forage_type~';
  1308. var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/;
  1309. var SERIALIZED_MARKER = '__lfsc__:';
  1310. var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
  1311. // OMG the serializations!
  1312. var TYPE_ARRAYBUFFER = 'arbf';
  1313. var TYPE_BLOB = 'blob';
  1314. var TYPE_INT8ARRAY = 'si08';
  1315. var TYPE_UINT8ARRAY = 'ui08';
  1316. var TYPE_UINT8CLAMPEDARRAY = 'uic8';
  1317. var TYPE_INT16ARRAY = 'si16';
  1318. var TYPE_INT32ARRAY = 'si32';
  1319. var TYPE_UINT16ARRAY = 'ur16';
  1320. var TYPE_UINT32ARRAY = 'ui32';
  1321. var TYPE_FLOAT32ARRAY = 'fl32';
  1322. var TYPE_FLOAT64ARRAY = 'fl64';
  1323. var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + TYPE_ARRAYBUFFER.length;
  1324. // Abstracts constructing a Blob object, so it also works in older
  1325. // browsers that don't support the native Blob constructor. (i.e.
  1326. // old QtWebKit versions, at least).
  1327. function _createBlob(parts, properties) {
  1328. parts = parts || [];
  1329. properties = properties || {};
  1330. try {
  1331. return new Blob(parts, properties);
  1332. } catch (err) {
  1333. if (err.name !== 'TypeError') {
  1334. throw err;
  1335. }
  1336. var BlobBuilder = globalObject.BlobBuilder || globalObject.MSBlobBuilder || globalObject.MozBlobBuilder || globalObject.WebKitBlobBuilder;
  1337. var builder = new BlobBuilder();
  1338. for (var i = 0; i < parts.length; i += 1) {
  1339. builder.append(parts[i]);
  1340. }
  1341. return builder.getBlob(properties.type);
  1342. }
  1343. }
  1344. // Serialize a value, afterwards executing a callback (which usually
  1345. // instructs the `setItem()` callback/promise to be executed). This is how
  1346. // we store binary data with localStorage.
  1347. function serialize(value, callback) {
  1348. var valueString = '';
  1349. if (value) {
  1350. valueString = value.toString();
  1351. }
  1352. // Cannot use `value instanceof ArrayBuffer` or such here, as these
  1353. // checks fail when running the tests using casper.js...
  1354. //
  1355. // TODO: See why those tests fail and use a better solution.
  1356. if (value && (value.toString() === '[object ArrayBuffer]' || value.buffer && value.buffer.toString() === '[object ArrayBuffer]')) {
  1357. // Convert binary arrays to a string and prefix the string with
  1358. // a special marker.
  1359. var buffer;
  1360. var marker = SERIALIZED_MARKER;
  1361. if (value instanceof ArrayBuffer) {
  1362. buffer = value;
  1363. marker += TYPE_ARRAYBUFFER;
  1364. } else {
  1365. buffer = value.buffer;
  1366. if (valueString === '[object Int8Array]') {
  1367. marker += TYPE_INT8ARRAY;
  1368. } else if (valueString === '[object Uint8Array]') {
  1369. marker += TYPE_UINT8ARRAY;
  1370. } else if (valueString === '[object Uint8ClampedArray]') {
  1371. marker += TYPE_UINT8CLAMPEDARRAY;
  1372. } else if (valueString === '[object Int16Array]') {
  1373. marker += TYPE_INT16ARRAY;
  1374. } else if (valueString === '[object Uint16Array]') {
  1375. marker += TYPE_UINT16ARRAY;
  1376. } else if (valueString === '[object Int32Array]') {
  1377. marker += TYPE_INT32ARRAY;
  1378. } else if (valueString === '[object Uint32Array]') {
  1379. marker += TYPE_UINT32ARRAY;
  1380. } else if (valueString === '[object Float32Array]') {
  1381. marker += TYPE_FLOAT32ARRAY;
  1382. } else if (valueString === '[object Float64Array]') {
  1383. marker += TYPE_FLOAT64ARRAY;
  1384. } else {
  1385. callback(new Error('Failed to get type for BinaryArray'));
  1386. }
  1387. }
  1388. callback(marker + bufferToString(buffer));
  1389. } else if (valueString === '[object Blob]') {
  1390. // Conver the blob to a binaryArray and then to a string.
  1391. var fileReader = new FileReader();
  1392. fileReader.onload = function () {
  1393. // Backwards-compatible prefix for the blob type.
  1394. var str = BLOB_TYPE_PREFIX + value.type + '~' + bufferToString(this.result);
  1395. callback(SERIALIZED_MARKER + TYPE_BLOB + str);
  1396. };
  1397. fileReader.readAsArrayBuffer(value);
  1398. } else {
  1399. try {
  1400. callback(JSON.stringify(value));
  1401. } catch (e) {
  1402. console.error("Couldn't convert value into a JSON string: ", value);
  1403. callback(null, e);
  1404. }
  1405. }
  1406. }
  1407. // Deserialize data we've inserted into a value column/field. We place
  1408. // special markers into our strings to mark them as encoded; this isn't
  1409. // as nice as a meta field, but it's the only sane thing we can do whilst
  1410. // keeping localStorage support intact.
  1411. //
  1412. // Oftentimes this will just deserialize JSON content, but if we have a
  1413. // special marker (SERIALIZED_MARKER, defined above), we will extract
  1414. // some kind of arraybuffer/binary data/typed array out of the string.
  1415. function deserialize(value) {
  1416. // If we haven't marked this string as being specially serialized (i.e.
  1417. // something other than serialized JSON), we can just return it and be
  1418. // done with it.
  1419. if (value.substring(0, SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
  1420. return JSON.parse(value);
  1421. }
  1422. // The following code deals with deserializing some kind of Blob or
  1423. // TypedArray. First we separate out the type of data we're dealing
  1424. // with from the data itself.
  1425. var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
  1426. var type = value.substring(SERIALIZED_MARKER_LENGTH, TYPE_SERIALIZED_MARKER_LENGTH);
  1427. var blobType;
  1428. // Backwards-compatible blob type serialization strategy.
  1429. // DBs created with older versions of localForage will simply not have the blob type.
  1430. if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) {
  1431. var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX);
  1432. blobType = matcher[1];
  1433. serializedString = serializedString.substring(matcher[0].length);
  1434. }
  1435. var buffer = stringToBuffer(serializedString);
  1436. // Return the right type based on the code/type set during
  1437. // serialization.
  1438. switch (type) {
  1439. case TYPE_ARRAYBUFFER:
  1440. return buffer;
  1441. case TYPE_BLOB:
  1442. return _createBlob([buffer], { type: blobType });
  1443. case TYPE_INT8ARRAY:
  1444. return new Int8Array(buffer);
  1445. case TYPE_UINT8ARRAY:
  1446. return new Uint8Array(buffer);
  1447. case TYPE_UINT8CLAMPEDARRAY:
  1448. return new Uint8ClampedArray(buffer);
  1449. case TYPE_INT16ARRAY:
  1450. return new Int16Array(buffer);
  1451. case TYPE_UINT16ARRAY:
  1452. return new Uint16Array(buffer);
  1453. case TYPE_INT32ARRAY:
  1454. return new Int32Array(buffer);
  1455. case TYPE_UINT32ARRAY:
  1456. return new Uint32Array(buffer);
  1457. case TYPE_FLOAT32ARRAY:
  1458. return new Float32Array(buffer);
  1459. case TYPE_FLOAT64ARRAY:
  1460. return new Float64Array(buffer);
  1461. default:
  1462. throw new Error('Unkown type: ' + type);
  1463. }
  1464. }
  1465. function stringToBuffer(serializedString) {
  1466. // Fill the string into a ArrayBuffer.
  1467. var bufferLength = serializedString.length * 0.75;
  1468. var len = serializedString.length;
  1469. var i;
  1470. var p = 0;
  1471. var encoded1, encoded2, encoded3, encoded4;
  1472. if (serializedString[serializedString.length - 1] === '=') {
  1473. bufferLength--;
  1474. if (serializedString[serializedString.length - 2] === '=') {
  1475. bufferLength--;
  1476. }
  1477. }
  1478. var buffer = new ArrayBuffer(bufferLength);
  1479. var bytes = new Uint8Array(buffer);
  1480. for (i = 0; i < len; i += 4) {
  1481. encoded1 = BASE_CHARS.indexOf(serializedString[i]);
  1482. encoded2 = BASE_CHARS.indexOf(serializedString[i + 1]);
  1483. encoded3 = BASE_CHARS.indexOf(serializedString[i + 2]);
  1484. encoded4 = BASE_CHARS.indexOf(serializedString[i + 3]);
  1485. /*jslint bitwise: true */
  1486. bytes[p++] = encoded1 << 2 | encoded2 >> 4;
  1487. bytes[p++] = (encoded2 & 15) << 4 | encoded3 >> 2;
  1488. bytes[p++] = (encoded3 & 3) << 6 | encoded4 & 63;
  1489. }
  1490. return buffer;
  1491. }
  1492. // Converts a buffer to a string to store, serialized, in the backend
  1493. // storage library.
  1494. function bufferToString(buffer) {
  1495. // base64-arraybuffer
  1496. var bytes = new Uint8Array(buffer);
  1497. var base64String = '';
  1498. var i;
  1499. for (i = 0; i < bytes.length; i += 3) {
  1500. /*jslint bitwise: true */
  1501. base64String += BASE_CHARS[bytes[i] >> 2];
  1502. base64String += BASE_CHARS[(bytes[i] & 3) << 4 | bytes[i + 1] >> 4];
  1503. base64String += BASE_CHARS[(bytes[i + 1] & 15) << 2 | bytes[i + 2] >> 6];
  1504. base64String += BASE_CHARS[bytes[i + 2] & 63];
  1505. }
  1506. if (bytes.length % 3 === 2) {
  1507. base64String = base64String.substring(0, base64String.length - 1) + '=';
  1508. } else if (bytes.length % 3 === 1) {
  1509. base64String = base64String.substring(0, base64String.length - 2) + '==';
  1510. }
  1511. return base64String;
  1512. }
  1513. var localforageSerializer = {
  1514. serialize: serialize,
  1515. deserialize: deserialize,
  1516. stringToBuffer: stringToBuffer,
  1517. bufferToString: bufferToString
  1518. };
  1519. return localforageSerializer;
  1520. })(typeof window !== 'undefined' ? window : self);
  1521. exports['default'] = localforageSerializer;
  1522. module.exports = exports['default'];
  1523. /***/ },
  1524. /* 4 */
  1525. /***/ function(module, exports, __webpack_require__) {
  1526. /*
  1527. * Includes code from:
  1528. *
  1529. * base64-arraybuffer
  1530. * https://github.com/niklasvh/base64-arraybuffer
  1531. *
  1532. * Copyright (c) 2012 Niklas von Hertzen
  1533. * Licensed under the MIT license.
  1534. */
  1535. 'use strict';
  1536. exports.__esModule = true;
  1537. var webSQLStorage = (function (globalObject) {
  1538. 'use strict';
  1539. var openDatabase = globalObject.openDatabase;
  1540. // If WebSQL methods aren't available, we can stop now.
  1541. if (!openDatabase) {
  1542. return;
  1543. }
  1544. // Open the WebSQL database (automatically creates one if one didn't
  1545. // previously exist), using any options set in the config.
  1546. function _initStorage(options) {
  1547. var self = this;
  1548. var dbInfo = {
  1549. db: null
  1550. };
  1551. if (options) {
  1552. for (var i in options) {
  1553. dbInfo[i] = typeof options[i] !== 'string' ? options[i].toString() : options[i];
  1554. }
  1555. }
  1556. var dbInfoPromise = new Promise(function (resolve, reject) {
  1557. // Open the database; the openDatabase API will automatically
  1558. // create it for us if it doesn't exist.
  1559. try {
  1560. dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version), dbInfo.description, dbInfo.size);
  1561. } catch (e) {
  1562. return reject(e);
  1563. }
  1564. // Create our key/value table if it doesn't exist.
  1565. dbInfo.db.transaction(function (t) {
  1566. t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName + ' (id INTEGER PRIMARY KEY, key unique, value)', [], function () {
  1567. self._dbInfo = dbInfo;
  1568. resolve();
  1569. }, function (t, error) {
  1570. reject(error);
  1571. });
  1572. });
  1573. });
  1574. return new Promise(function (resolve, reject) {
  1575. resolve(__webpack_require__(3));
  1576. }).then(function (lib) {
  1577. dbInfo.serializer = lib;
  1578. return dbInfoPromise;
  1579. });
  1580. }
  1581. function getItem(key, callback) {
  1582. var self = this;
  1583. // Cast the key to a string, as that's all we can set as a key.
  1584. if (typeof key !== 'string') {
  1585. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  1586. key = String(key);
  1587. }
  1588. var promise = new Promise(function (resolve, reject) {
  1589. self.ready().then(function () {
  1590. var dbInfo = self._dbInfo;
  1591. dbInfo.db.transaction(function (t) {
  1592. t.executeSql('SELECT * FROM ' + dbInfo.storeName + ' WHERE key = ? LIMIT 1', [key], function (t, results) {
  1593. var result = results.rows.length ? results.rows.item(0).value : null;
  1594. // Check to see if this is serialized content we need to
  1595. // unpack.
  1596. if (result) {
  1597. result = dbInfo.serializer.deserialize(result);
  1598. }
  1599. resolve(result);
  1600. }, function (t, error) {
  1601. reject(error);
  1602. });
  1603. });
  1604. })['catch'](reject);
  1605. });
  1606. executeCallback(promise, callback);
  1607. return promise;
  1608. }
  1609. function iterate(iterator, callback) {
  1610. var self = this;
  1611. var promise = new Promise(function (resolve, reject) {
  1612. self.ready().then(function () {
  1613. var dbInfo = self._dbInfo;
  1614. dbInfo.db.transaction(function (t) {
  1615. t.executeSql('SELECT * FROM ' + dbInfo.storeName, [], function (t, results) {
  1616. var rows = results.rows;
  1617. var length = rows.length;
  1618. for (var i = 0; i < length; i++) {
  1619. var item = rows.item(i);
  1620. var result = item.value;
  1621. // Check to see if this is serialized content
  1622. // we need to unpack.
  1623. if (result) {
  1624. result = dbInfo.serializer.deserialize(result);
  1625. }
  1626. result = iterator(result, item.key, i + 1);
  1627. // void(0) prevents problems with redefinition
  1628. // of `undefined`.
  1629. if (result !== void 0) {
  1630. resolve(result);
  1631. return;
  1632. }
  1633. }
  1634. resolve();
  1635. }, function (t, error) {
  1636. reject(error);
  1637. });
  1638. });
  1639. })['catch'](reject);
  1640. });
  1641. executeCallback(promise, callback);
  1642. return promise;
  1643. }
  1644. function setItem(key, value, callback) {
  1645. var self = this;
  1646. // Cast the key to a string, as that's all we can set as a key.
  1647. if (typeof key !== 'string') {
  1648. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  1649. key = String(key);
  1650. }
  1651. var promise = new Promise(function (resolve, reject) {
  1652. self.ready().then(function () {
  1653. // The localStorage API doesn't return undefined values in an
  1654. // "expected" way, so undefined is always cast to null in all
  1655. // drivers. See: https://github.com/mozilla/localForage/pull/42
  1656. if (value === undefined) {
  1657. value = null;
  1658. }
  1659. // Save the original value to pass to the callback.
  1660. var originalValue = value;
  1661. var dbInfo = self._dbInfo;
  1662. dbInfo.serializer.serialize(value, function (value, error) {
  1663. if (error) {
  1664. reject(error);
  1665. } else {
  1666. dbInfo.db.transaction(function (t) {
  1667. t.executeSql('INSERT OR REPLACE INTO ' + dbInfo.storeName + ' (key, value) VALUES (?, ?)', [key, value], function () {
  1668. resolve(originalValue);
  1669. }, function (t, error) {
  1670. reject(error);
  1671. });
  1672. }, function (sqlError) {
  1673. // The transaction failed; check
  1674. // to see if it's a quota error.
  1675. if (sqlError.code === sqlError.QUOTA_ERR) {
  1676. // We reject the callback outright for now, but
  1677. // it's worth trying to re-run the transaction.
  1678. // Even if the user accepts the prompt to use
  1679. // more storage on Safari, this error will
  1680. // be called.
  1681. //
  1682. // TODO: Try to re-run the transaction.
  1683. reject(sqlError);
  1684. }
  1685. });
  1686. }
  1687. });
  1688. })['catch'](reject);
  1689. });
  1690. executeCallback(promise, callback);
  1691. return promise;
  1692. }
  1693. function removeItem(key, callback) {
  1694. var self = this;
  1695. // Cast the key to a string, as that's all we can set as a key.
  1696. if (typeof key !== 'string') {
  1697. globalObject.console.warn(key + ' used as a key, but it is not a string.');
  1698. key = String(key);
  1699. }
  1700. var promise = new Promise(function (resolve, reject) {
  1701. self.ready().then(function () {
  1702. var dbInfo = self._dbInfo;
  1703. dbInfo.db.transaction(function (t) {
  1704. t.executeSql('DELETE FROM ' + dbInfo.storeName + ' WHERE key = ?', [key], function () {
  1705. resolve();
  1706. }, function (t, error) {
  1707. reject(error);
  1708. });
  1709. });
  1710. })['catch'](reject);
  1711. });
  1712. executeCallback(promise, callback);
  1713. return promise;
  1714. }
  1715. // Deletes every item in the table.
  1716. // TODO: Find out if this resets the AUTO_INCREMENT number.
  1717. function clear(callback) {
  1718. var self = this;
  1719. var promise = new Promise(function (resolve, reject) {
  1720. self.ready().then(function () {
  1721. var dbInfo = self._dbInfo;
  1722. dbInfo.db.transaction(function (t) {
  1723. t.executeSql('DELETE FROM ' + dbInfo.storeName, [], function () {
  1724. resolve();
  1725. }, function (t, error) {
  1726. reject(error);
  1727. });
  1728. });
  1729. })['catch'](reject);
  1730. });
  1731. executeCallback(promise, callback);
  1732. return promise;
  1733. }
  1734. // Does a simple `COUNT(key)` to get the number of items stored in
  1735. // localForage.
  1736. function length(callback) {
  1737. var self = this;
  1738. var promise = new Promise(function (resolve, reject) {
  1739. self.ready().then(function () {
  1740. var dbInfo = self._dbInfo;
  1741. dbInfo.db.transaction(function (t) {
  1742. // Ahhh, SQL makes this one soooooo easy.
  1743. t.executeSql('SELECT COUNT(key) as c FROM ' + dbInfo.storeName, [], function (t, results) {
  1744. var result = results.rows.item(0).c;
  1745. resolve(result);
  1746. }, function (t, error) {
  1747. reject(error);
  1748. });
  1749. });
  1750. })['catch'](reject);
  1751. });
  1752. executeCallback(promise, callback);
  1753. return promise;
  1754. }
  1755. // Return the key located at key index X; essentially gets the key from a
  1756. // `WHERE id = ?`. This is the most efficient way I can think to implement
  1757. // this rarely-used (in my experience) part of the API, but it can seem
  1758. // inconsistent, because we do `INSERT OR REPLACE INTO` on `setItem()`, so
  1759. // the ID of each key will change every time it's updated. Perhaps a stored
  1760. // procedure for the `setItem()` SQL would solve this problem?
  1761. // TODO: Don't change ID on `setItem()`.
  1762. function key(n, callback) {
  1763. var self = this;
  1764. var promise = new Promise(function (resolve, reject) {
  1765. self.ready().then(function () {
  1766. var dbInfo = self._dbInfo;
  1767. dbInfo.db.transaction(function (t) {
  1768. t.executeSql('SELECT key FROM ' + dbInfo.storeName + ' WHERE id = ? LIMIT 1', [n + 1], function (t, results) {
  1769. var result = results.rows.length ? results.rows.item(0).key : null;
  1770. resolve(result);
  1771. }, function (t, error) {
  1772. reject(error);
  1773. });
  1774. });
  1775. })['catch'](reject);
  1776. });
  1777. executeCallback(promise, callback);
  1778. return promise;
  1779. }
  1780. function keys(callback) {
  1781. var self = this;
  1782. var promise = new Promise(function (resolve, reject) {
  1783. self.ready().then(function () {
  1784. var dbInfo = self._dbInfo;
  1785. dbInfo.db.transaction(function (t) {
  1786. t.executeSql('SELECT key FROM ' + dbInfo.storeName, [], function (t, results) {
  1787. var keys = [];
  1788. for (var i = 0; i < results.rows.length; i++) {
  1789. keys.push(results.rows.item(i).key);
  1790. }
  1791. resolve(keys);
  1792. }, function (t, error) {
  1793. reject(error);
  1794. });
  1795. });
  1796. })['catch'](reject);
  1797. });
  1798. executeCallback(promise, callback);
  1799. return promise;
  1800. }
  1801. function executeCallback(promise, callback) {
  1802. if (callback) {
  1803. promise.then(function (result) {
  1804. callback(null, result);
  1805. }, function (error) {
  1806. callback(error);
  1807. });
  1808. }
  1809. }
  1810. var webSQLStorage = {
  1811. _driver: 'webSQLStorage',
  1812. _initStorage: _initStorage,
  1813. iterate: iterate,
  1814. getItem: getItem,
  1815. setItem: setItem,
  1816. removeItem: removeItem,
  1817. clear: clear,
  1818. length: length,
  1819. key: key,
  1820. keys: keys
  1821. };
  1822. return webSQLStorage;
  1823. })(typeof window !== 'undefined' ? window : self);
  1824. exports['default'] = webSQLStorage;
  1825. module.exports = exports['default'];
  1826. /***/ }
  1827. /******/ ])
  1828. });
  1829. ;