Repositorio del curso CCOM4030 el semestre B91 del proyecto Artesanías con el Instituto de Cultura

localforage.js 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. import idbDriver from './drivers/indexeddb';
  2. import websqlDriver from './drivers/websql';
  3. import localstorageDriver from './drivers/localstorage';
  4. import serializer from './utils/serializer';
  5. import Promise from './utils/promise';
  6. import executeCallback from './utils/executeCallback';
  7. import executeTwoCallbacks from './utils/executeTwoCallbacks';
  8. import includes from './utils/includes';
  9. import isArray from './utils/isArray';
  10. // Drivers are stored here when `defineDriver()` is called.
  11. // They are shared across all instances of localForage.
  12. const DefinedDrivers = {};
  13. const DriverSupport = {};
  14. const DefaultDrivers = {
  15. INDEXEDDB: idbDriver,
  16. WEBSQL: websqlDriver,
  17. LOCALSTORAGE: localstorageDriver
  18. };
  19. const DefaultDriverOrder = [
  20. DefaultDrivers.INDEXEDDB._driver,
  21. DefaultDrivers.WEBSQL._driver,
  22. DefaultDrivers.LOCALSTORAGE._driver
  23. ];
  24. const OptionalDriverMethods = ['dropInstance'];
  25. const LibraryMethods = [
  26. 'clear',
  27. 'getItem',
  28. 'iterate',
  29. 'key',
  30. 'keys',
  31. 'length',
  32. 'removeItem',
  33. 'setItem'
  34. ].concat(OptionalDriverMethods);
  35. const DefaultConfig = {
  36. description: '',
  37. driver: DefaultDriverOrder.slice(),
  38. name: 'localforage',
  39. // Default DB size is _JUST UNDER_ 5MB, as it's the highest size
  40. // we can use without a prompt.
  41. size: 4980736,
  42. storeName: 'keyvaluepairs',
  43. version: 1.0
  44. };
  45. function callWhenReady(localForageInstance, libraryMethod) {
  46. localForageInstance[libraryMethod] = function() {
  47. const _args = arguments;
  48. return localForageInstance.ready().then(function() {
  49. return localForageInstance[libraryMethod].apply(
  50. localForageInstance,
  51. _args
  52. );
  53. });
  54. };
  55. }
  56. function extend() {
  57. for (let i = 1; i < arguments.length; i++) {
  58. const arg = arguments[i];
  59. if (arg) {
  60. for (let key in arg) {
  61. if (arg.hasOwnProperty(key)) {
  62. if (isArray(arg[key])) {
  63. arguments[0][key] = arg[key].slice();
  64. } else {
  65. arguments[0][key] = arg[key];
  66. }
  67. }
  68. }
  69. }
  70. }
  71. return arguments[0];
  72. }
  73. class LocalForage {
  74. constructor(options) {
  75. for (let driverTypeKey in DefaultDrivers) {
  76. if (DefaultDrivers.hasOwnProperty(driverTypeKey)) {
  77. const driver = DefaultDrivers[driverTypeKey];
  78. const driverName = driver._driver;
  79. this[driverTypeKey] = driverName;
  80. if (!DefinedDrivers[driverName]) {
  81. // we don't need to wait for the promise,
  82. // since the default drivers can be defined
  83. // in a blocking manner
  84. this.defineDriver(driver);
  85. }
  86. }
  87. }
  88. this._defaultConfig = extend({}, DefaultConfig);
  89. this._config = extend({}, this._defaultConfig, options);
  90. this._driverSet = null;
  91. this._initDriver = null;
  92. this._ready = false;
  93. this._dbInfo = null;
  94. this._wrapLibraryMethodsWithReady();
  95. this.setDriver(this._config.driver).catch(() => {});
  96. }
  97. // Set any config values for localForage; can be called anytime before
  98. // the first API call (e.g. `getItem`, `setItem`).
  99. // We loop through options so we don't overwrite existing config
  100. // values.
  101. config(options) {
  102. // If the options argument is an object, we use it to set values.
  103. // Otherwise, we return either a specified config value or all
  104. // config values.
  105. if (typeof options === 'object') {
  106. // If localforage is ready and fully initialized, we can't set
  107. // any new configuration values. Instead, we return an error.
  108. if (this._ready) {
  109. return new Error(
  110. "Can't call config() after localforage " + 'has been used.'
  111. );
  112. }
  113. for (let i in options) {
  114. if (i === 'storeName') {
  115. options[i] = options[i].replace(/\W/g, '_');
  116. }
  117. if (i === 'version' && typeof options[i] !== 'number') {
  118. return new Error('Database version must be a number.');
  119. }
  120. this._config[i] = options[i];
  121. }
  122. // after all config options are set and
  123. // the driver option is used, try setting it
  124. if ('driver' in options && options.driver) {
  125. return this.setDriver(this._config.driver);
  126. }
  127. return true;
  128. } else if (typeof options === 'string') {
  129. return this._config[options];
  130. } else {
  131. return this._config;
  132. }
  133. }
  134. // Used to define a custom driver, shared across all instances of
  135. // localForage.
  136. defineDriver(driverObject, callback, errorCallback) {
  137. const promise = new Promise(function(resolve, reject) {
  138. try {
  139. const driverName = driverObject._driver;
  140. const complianceError = new Error(
  141. 'Custom driver not compliant; see ' +
  142. 'https://mozilla.github.io/localForage/#definedriver'
  143. );
  144. // A driver name should be defined and not overlap with the
  145. // library-defined, default drivers.
  146. if (!driverObject._driver) {
  147. reject(complianceError);
  148. return;
  149. }
  150. const driverMethods = LibraryMethods.concat('_initStorage');
  151. for (let i = 0, len = driverMethods.length; i < len; i++) {
  152. const driverMethodName = driverMethods[i];
  153. // when the property is there,
  154. // it should be a method even when optional
  155. const isRequired = !includes(
  156. OptionalDriverMethods,
  157. driverMethodName
  158. );
  159. if (
  160. (isRequired || driverObject[driverMethodName]) &&
  161. typeof driverObject[driverMethodName] !== 'function'
  162. ) {
  163. reject(complianceError);
  164. return;
  165. }
  166. }
  167. const configureMissingMethods = function() {
  168. const methodNotImplementedFactory = function(methodName) {
  169. return function() {
  170. const error = new Error(
  171. `Method ${methodName} is not implemented by the current driver`
  172. );
  173. const promise = Promise.reject(error);
  174. executeCallback(
  175. promise,
  176. arguments[arguments.length - 1]
  177. );
  178. return promise;
  179. };
  180. };
  181. for (
  182. let i = 0, len = OptionalDriverMethods.length;
  183. i < len;
  184. i++
  185. ) {
  186. const optionalDriverMethod = OptionalDriverMethods[i];
  187. if (!driverObject[optionalDriverMethod]) {
  188. driverObject[
  189. optionalDriverMethod
  190. ] = methodNotImplementedFactory(
  191. optionalDriverMethod
  192. );
  193. }
  194. }
  195. };
  196. configureMissingMethods();
  197. const setDriverSupport = function(support) {
  198. if (DefinedDrivers[driverName]) {
  199. console.info(
  200. `Redefining LocalForage driver: ${driverName}`
  201. );
  202. }
  203. DefinedDrivers[driverName] = driverObject;
  204. DriverSupport[driverName] = support;
  205. // don't use a then, so that we can define
  206. // drivers that have simple _support methods
  207. // in a blocking manner
  208. resolve();
  209. };
  210. if ('_support' in driverObject) {
  211. if (
  212. driverObject._support &&
  213. typeof driverObject._support === 'function'
  214. ) {
  215. driverObject._support().then(setDriverSupport, reject);
  216. } else {
  217. setDriverSupport(!!driverObject._support);
  218. }
  219. } else {
  220. setDriverSupport(true);
  221. }
  222. } catch (e) {
  223. reject(e);
  224. }
  225. });
  226. executeTwoCallbacks(promise, callback, errorCallback);
  227. return promise;
  228. }
  229. driver() {
  230. return this._driver || null;
  231. }
  232. getDriver(driverName, callback, errorCallback) {
  233. const getDriverPromise = DefinedDrivers[driverName]
  234. ? Promise.resolve(DefinedDrivers[driverName])
  235. : Promise.reject(new Error('Driver not found.'));
  236. executeTwoCallbacks(getDriverPromise, callback, errorCallback);
  237. return getDriverPromise;
  238. }
  239. getSerializer(callback) {
  240. const serializerPromise = Promise.resolve(serializer);
  241. executeTwoCallbacks(serializerPromise, callback);
  242. return serializerPromise;
  243. }
  244. ready(callback) {
  245. const self = this;
  246. const promise = self._driverSet.then(() => {
  247. if (self._ready === null) {
  248. self._ready = self._initDriver();
  249. }
  250. return self._ready;
  251. });
  252. executeTwoCallbacks(promise, callback, callback);
  253. return promise;
  254. }
  255. setDriver(drivers, callback, errorCallback) {
  256. const self = this;
  257. if (!isArray(drivers)) {
  258. drivers = [drivers];
  259. }
  260. const supportedDrivers = this._getSupportedDrivers(drivers);
  261. function setDriverToConfig() {
  262. self._config.driver = self.driver();
  263. }
  264. function extendSelfWithDriver(driver) {
  265. self._extend(driver);
  266. setDriverToConfig();
  267. self._ready = self._initStorage(self._config);
  268. return self._ready;
  269. }
  270. function initDriver(supportedDrivers) {
  271. return function() {
  272. let currentDriverIndex = 0;
  273. function driverPromiseLoop() {
  274. while (currentDriverIndex < supportedDrivers.length) {
  275. let driverName = supportedDrivers[currentDriverIndex];
  276. currentDriverIndex++;
  277. self._dbInfo = null;
  278. self._ready = null;
  279. return self
  280. .getDriver(driverName)
  281. .then(extendSelfWithDriver)
  282. .catch(driverPromiseLoop);
  283. }
  284. setDriverToConfig();
  285. const error = new Error(
  286. 'No available storage method found.'
  287. );
  288. self._driverSet = Promise.reject(error);
  289. return self._driverSet;
  290. }
  291. return driverPromiseLoop();
  292. };
  293. }
  294. // There might be a driver initialization in progress
  295. // so wait for it to finish in order to avoid a possible
  296. // race condition to set _dbInfo
  297. const oldDriverSetDone =
  298. this._driverSet !== null
  299. ? this._driverSet.catch(() => Promise.resolve())
  300. : Promise.resolve();
  301. this._driverSet = oldDriverSetDone
  302. .then(() => {
  303. const driverName = supportedDrivers[0];
  304. self._dbInfo = null;
  305. self._ready = null;
  306. return self.getDriver(driverName).then(driver => {
  307. self._driver = driver._driver;
  308. setDriverToConfig();
  309. self._wrapLibraryMethodsWithReady();
  310. self._initDriver = initDriver(supportedDrivers);
  311. });
  312. })
  313. .catch(() => {
  314. setDriverToConfig();
  315. const error = new Error('No available storage method found.');
  316. self._driverSet = Promise.reject(error);
  317. return self._driverSet;
  318. });
  319. executeTwoCallbacks(this._driverSet, callback, errorCallback);
  320. return this._driverSet;
  321. }
  322. supports(driverName) {
  323. return !!DriverSupport[driverName];
  324. }
  325. _extend(libraryMethodsAndProperties) {
  326. extend(this, libraryMethodsAndProperties);
  327. }
  328. _getSupportedDrivers(drivers) {
  329. const supportedDrivers = [];
  330. for (let i = 0, len = drivers.length; i < len; i++) {
  331. const driverName = drivers[i];
  332. if (this.supports(driverName)) {
  333. supportedDrivers.push(driverName);
  334. }
  335. }
  336. return supportedDrivers;
  337. }
  338. _wrapLibraryMethodsWithReady() {
  339. // Add a stub for each driver API method that delays the call to the
  340. // corresponding driver method until localForage is ready. These stubs
  341. // will be replaced by the driver methods as soon as the driver is
  342. // loaded, so there is no performance impact.
  343. for (let i = 0, len = LibraryMethods.length; i < len; i++) {
  344. callWhenReady(this, LibraryMethods[i]);
  345. }
  346. }
  347. createInstance(options) {
  348. return new LocalForage(options);
  349. }
  350. }
  351. // The actual localForage object that we expose as a module or via a
  352. // global. It's extended by pulling in one of our other libraries.
  353. export default new LocalForage();