diff options
author | Aaron Parecki <aaron@parecki.com> | 2016-04-21 07:48:16 -0700 |
---|---|---|
committer | Aaron Parecki <aaron@parecki.com> | 2016-04-21 07:48:16 -0700 |
commit | 904782f973a12542cacb394e2e1d0827accd995a (patch) | |
tree | 66f5ef63678ba61f9cfdc69cc6682bc51a57c05b /public/editor/localforage | |
parent | d0055bad24153e1dc696df2b8825dba4c523b434 (diff) |
move editor folder to editor-files, remove appcache
* it sometimes confuses web servers to have a folder named "editor" while also serving routes with the same name
* dropped appcache stuff since it wasn't working super well
* add nginx config to the readme
Diffstat (limited to 'public/editor/localforage')
-rw-r--r-- | public/editor/localforage/localforage.js | 2497 |
1 files changed, 0 insertions, 2497 deletions
diff --git a/public/editor/localforage/localforage.js b/public/editor/localforage/localforage.js deleted file mode 100644 index 42e5391..0000000 --- a/public/editor/localforage/localforage.js +++ /dev/null @@ -1,2497 +0,0 @@ -/*! - localForage -- Offline Storage, Improved - Version 1.2.2 - https://mozilla.github.io/localForage - (c) 2013-2015 Mozilla, Apache License 2.0 -*/ -(function() { -var define, requireModule, require, requirejs; - -(function() { - var registry = {}, seen = {}; - - define = function(name, deps, callback) { - registry[name] = { deps: deps, callback: callback }; - }; - - requirejs = require = requireModule = function(name) { - requirejs._eak_seen = registry; - - if (seen[name]) { return seen[name]; } - seen[name] = {}; - - if (!registry[name]) { - throw new Error("Could not find module " + name); - } - - var mod = registry[name], - deps = mod.deps, - callback = mod.callback, - reified = [], - exports; - - for (var i=0, l=deps.length; i<l; i++) { - if (deps[i] === 'exports') { - reified.push(exports = {}); - } else { - reified.push(requireModule(resolve(deps[i]))); - } - } - - var value = callback.apply(this, reified); - return seen[name] = exports || value; - - function resolve(child) { - if (child.charAt(0) !== '.') { return child; } - var parts = child.split("/"); - var parentBase = name.split("/").slice(0, -1); - - for (var i=0, l=parts.length; i<l; i++) { - var part = parts[i]; - - if (part === '..') { parentBase.pop(); } - else if (part === '.') { continue; } - else { parentBase.push(part); } - } - - return parentBase.join("/"); - } - }; -})(); - -define("promise/all", - ["./utils","exports"], - function(__dependency1__, __exports__) { - "use strict"; - /* global toString */ - - var isArray = __dependency1__.isArray; - var isFunction = __dependency1__.isFunction; - - /** - Returns a promise that is fulfilled when all the given promises have been - fulfilled, or rejected if any of them become rejected. The return promise - is fulfilled with an array that gives all the values in the order they were - passed in the `promises` array argument. - - Example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.resolve(2); - var promise3 = RSVP.resolve(3); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.all(promises).then(function(array){ - // The array here would be [ 1, 2, 3 ]; - }); - ``` - - If any of the `promises` given to `RSVP.all` are rejected, the first promise - that is rejected will be given as an argument to the returned promises's - rejection handler. For example: - - Example: - - ```javascript - var promise1 = RSVP.resolve(1); - var promise2 = RSVP.reject(new Error("2")); - var promise3 = RSVP.reject(new Error("3")); - var promises = [ promise1, promise2, promise3 ]; - - RSVP.all(promises).then(function(array){ - // Code here never runs because there are rejected promises! - }, function(error) { - // error.message === "2" - }); - ``` - - @method all - @for RSVP - @param {Array} promises - @param {String} label - @return {Promise} promise that is fulfilled when all `promises` have been - fulfilled, or rejected if any of them become rejected. - */ - function all(promises) { - /*jshint validthis:true */ - var Promise = this; - - if (!isArray(promises)) { - throw new TypeError('You must pass an array to all.'); - } - - return new Promise(function(resolve, reject) { - var results = [], remaining = promises.length, - promise; - - if (remaining === 0) { - resolve([]); - } - - function resolver(index) { - return function(value) { - resolveAll(index, value); - }; - } - - function resolveAll(index, value) { - results[index] = value; - if (--remaining === 0) { - resolve(results); - } - } - - for (var i = 0; i < promises.length; i++) { - promise = promises[i]; - - if (promise && isFunction(promise.then)) { - promise.then(resolver(i), reject); - } else { - resolveAll(i, promise); - } - } - }); - } - - __exports__.all = all; - }); -define("promise/asap", - ["exports"], - function(__exports__) { - "use strict"; - var browserGlobal = (typeof window !== 'undefined') ? window : {}; - var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver; - var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this); - - // node - function useNextTick() { - return function() { - process.nextTick(flush); - }; - } - - function useMutationObserver() { - var iterations = 0; - var observer = new BrowserMutationObserver(flush); - var node = document.createTextNode(''); - observer.observe(node, { characterData: true }); - - return function() { - node.data = (iterations = ++iterations % 2); - }; - } - - function useSetTimeout() { - return function() { - local.setTimeout(flush, 1); - }; - } - - var queue = []; - function flush() { - for (var i = 0; i < queue.length; i++) { - var tuple = queue[i]; - var callback = tuple[0], arg = tuple[1]; - callback(arg); - } - queue = []; - } - - var scheduleFlush; - - // Decide what async method to use to triggering processing of queued callbacks: - if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') { - scheduleFlush = useNextTick(); - } else if (BrowserMutationObserver) { - scheduleFlush = useMutationObserver(); - } else { - scheduleFlush = useSetTimeout(); - } - - function asap(callback, arg) { - var length = queue.push([callback, arg]); - if (length === 1) { - // If length is 1, that means that we need to schedule an async flush. - // If additional callbacks are queued before the queue is flushed, they - // will be processed by this flush that we are scheduling. - scheduleFlush(); - } - } - - __exports__.asap = asap; - }); -define("promise/config", - ["exports"], - function(__exports__) { - "use strict"; - var config = { - instrument: false - }; - - function configure(name, value) { - if (arguments.length === 2) { - config[name] = value; - } else { - return config[name]; - } - } - - __exports__.config = config; - __exports__.configure = configure; - }); -define("promise/polyfill", - ["./promise","./utils","exports"], - function(__dependency1__, __dependency2__, __exports__) { - "use strict"; - /*global self*/ - var RSVPPromise = __dependency1__.Promise; - var isFunction = __dependency2__.isFunction; - - function polyfill() { - var local; - - if (typeof global !== 'undefined') { - local = global; - } else if (typeof window !== 'undefined' && window.document) { - local = window; - } else { - local = self; - } - - var es6PromiseSupport = - "Promise" in local && - // Some of these methods are missing from - // Firefox/Chrome experimental implementations - "resolve" in local.Promise && - "reject" in local.Promise && - "all" in local.Promise && - "race" in local.Promise && - // Older version of the spec had a resolver object - // as the arg rather than a function - (function() { - var resolve; - new local.Promise(function(r) { resolve = r; }); - return isFunction(resolve); - }()); - - if (!es6PromiseSupport) { - local.Promise = RSVPPromise; - } - } - - __exports__.polyfill = polyfill; - }); -define("promise/promise", - ["./config","./utils","./all","./race","./resolve","./reject","./asap","exports"], - function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __exports__) { - "use strict"; - var config = __dependency1__.config; - var configure = __dependency1__.configure; - var objectOrFunction = __dependency2__.objectOrFunction; - var isFunction = __dependency2__.isFunction; - var now = __dependency2__.now; - var all = __dependency3__.all; - var race = __dependency4__.race; - var staticResolve = __dependency5__.resolve; - var staticReject = __dependency6__.reject; - var asap = __dependency7__.asap; - - var counter = 0; - - config.async = asap; // default async is asap; - - function Promise(resolver) { - if (!isFunction(resolver)) { - throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); - } - - if (!(this instanceof Promise)) { - throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); - } - - this._subscribers = []; - - invokeResolver(resolver, this); - } - - function invokeResolver(resolver, promise) { - function resolvePromise(value) { - resolve(promise, value); - } - - function rejectPromise(reason) { - reject(promise, reason); - } - - try { - resolver(resolvePromise, rejectPromise); - } catch(e) { - rejectPromise(e); - } - } - - function invokeCallback(settled, promise, callback, detail) { - var hasCallback = isFunction(callback), - value, error, succeeded, failed; - - if (hasCallback) { - try { - value = callback(detail); - succeeded = true; - } catch(e) { - failed = true; - error = e; - } - } else { - value = detail; - succeeded = true; - } - - if (handleThenable(promise, value)) { - return; - } else if (hasCallback && succeeded) { - resolve(promise, value); - } else if (failed) { - reject(promise, error); - } else if (settled === FULFILLED) { - resolve(promise, value); - } else if (settled === REJECTED) { - reject(promise, value); - } - } - - var PENDING = void 0; - var SEALED = 0; - var FULFILLED = 1; - var REJECTED = 2; - - function subscribe(parent, child, onFulfillment, onRejection) { - var subscribers = parent._subscribers; - var length = subscribers.length; - - subscribers[length] = child; - subscribers[length + FULFILLED] = onFulfillment; - subscribers[length + REJECTED] = onRejection; - } - - function publish(promise, settled) { - var child, callback, subscribers = promise._subscribers, detail = promise._detail; - - for (var i = 0; i < subscribers.length; i += 3) { - child = subscribers[i]; - callback = subscribers[i + settled]; - - invokeCallback(settled, child, callback, detail); - } - - promise._subscribers = null; - } - - Promise.prototype = { - constructor: Promise, - - _state: undefined, - _detail: undefined, - _subscribers: undefined, - - then: function(onFulfillment, onRejection) { - var promise = this; - - var thenPromise = new this.constructor(function() {}); - - if (this._state) { - var callbacks = arguments; - config.async(function invokePromiseCallback() { - invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail); - }); - } else { - subscribe(this, thenPromise, onFulfillment, onRejection); - } - - return thenPromise; - }, - - 'catch': function(onRejection) { - return this.then(null, onRejection); - } - }; - - Promise.all = all; - Promise.race = race; - Promise.resolve = staticResolve; - Promise.reject = staticReject; - - function handleThenable(promise, value) { - var then = null, - resolved; - - try { - if (promise === value) { - throw new TypeError("A promises callback cannot return that same promise."); - } - - if (objectOrFunction(value)) { - then = value.then; - - if (isFunction(then)) { - then.call(value, function(val) { - if (resolved) { return true; } - resolved = true; - - if (value !== val) { - resolve(promise, val); - } else { - fulfill(promise, val); - } - }, function(val) { - if (resolved) { return true; } - resolved = true; - - reject(promise, val); - }); - - return true; - } - } - } catch (error) { - if (resolved) { return true; } - reject(promise, error); - return true; - } - - return false; - } - - function resolve(promise, value) { - if (promise === value) { - fulfill(promise, value); - } else if (!handleThenable(promise, value)) { - fulfill(promise, value); - } - } - - function fulfill(promise, value) { - if (promise._state !== PENDING) { return; } - promise._state = SEALED; - promise._detail = value; - - config.async(publishFulfillment, promise); - } - - function reject(promise, reason) { - if (promise._state !== PENDING) { return; } - promise._state = SEALED; - promise._detail = reason; - - config.async(publishRejection, promise); - } - - function publishFulfillment(promise) { - publish(promise, promise._state = FULFILLED); - } - - function publishRejection(promise) { - publish(promise, promise._state = REJECTED); - } - - __exports__.Promise = Promise; - }); -define("promise/race", - ["./utils","exports"], - function(__dependency1__, __exports__) { - "use strict"; - /* global toString */ - var isArray = __dependency1__.isArray; - - /** - `RSVP.race` allows you to watch a series of promises and act as soon as the - first promise given to the `promises` argument fulfills or rejects. - - Example: - - ```javascript - var promise1 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve("promise 1"); - }, 200); - }); - - var promise2 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve("promise 2"); - }, 100); - }); - - RSVP.race([promise1, promise2]).then(function(result){ - // result === "promise 2" because it was resolved before promise1 - // was resolved. - }); - ``` - - `RSVP.race` is deterministic in that only the state of the first completed - promise matters. For example, even if other promises given to the `promises` - array argument are resolved, but the first completed promise has become - rejected before the other promises became fulfilled, the returned promise - will become rejected: - - ```javascript - var promise1 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - resolve("promise 1"); - }, 200); - }); - - var promise2 = new RSVP.Promise(function(resolve, reject){ - setTimeout(function(){ - reject(new Error("promise 2")); - }, 100); - }); - - RSVP.race([promise1, promise2]).then(function(result){ - // Code here never runs because there are rejected promises! - }, function(reason){ - // reason.message === "promise2" because promise 2 became rejected before - // promise 1 became fulfilled - }); - ``` - - @method race - @for RSVP - @param {Array} promises array of promises to observe - @param {String} label optional string for describing the promise returned. - Useful for tooling. - @return {Promise} a promise that becomes fulfilled with the value the first - completed promises is resolved with if the first completed promise was - fulfilled, or rejected with the reason that the first completed promise - was rejected with. - */ - function race(promises) { - /*jshint validthis:true */ - var Promise = this; - - if (!isArray(promises)) { - throw new TypeError('You must pass an array to race.'); - } - return new Promise(function(resolve, reject) { - var results = [], promise; - - for (var i = 0; i < promises.length; i++) { - promise = promises[i]; - - if (promise && typeof promise.then === 'function') { - promise.then(resolve, reject); - } else { - resolve(promise); - } - } - }); - } - - __exports__.race = race; - }); -define("promise/reject", - ["exports"], - function(__exports__) { - "use strict"; - /** - `RSVP.reject` returns a promise that will become rejected with the passed - `reason`. `RSVP.reject` is essentially shorthand for the following: - - ```javascript - var promise = new RSVP.Promise(function(resolve, reject){ - reject(new Error('WHOOPS')); - }); - - promise.then(function(value){ - // Code here doesn't run because the promise is rejected! - }, function(reason){ - // reason.message === 'WHOOPS' - }); - ``` - - Instead of writing the above, your code now simply becomes the following: - - ```javascript - var promise = RSVP.reject(new Error('WHOOPS')); - - promise.then(function(value){ - // Code here doesn't run because the promise is rejected! - }, function(reason){ - // reason.message === 'WHOOPS' - }); - ``` - - @method reject - @for RSVP - @param {Any} reason value that the returned promise will be rejected with. - @param {String} label optional string for identifying the returned promise. - Useful for tooling. - @return {Promise} a promise that will become rejected with the given - `reason`. - */ - function reject(reason) { - /*jshint validthis:true */ - var Promise = this; - - return new Promise(function (resolve, reject) { - reject(reason); - }); - } - - __exports__.reject = reject; - }); -define("promise/resolve", - ["exports"], - function(__exports__) { - "use strict"; - function resolve(value) { - /*jshint validthis:true */ - if (value && typeof value === 'object' && value.constructor === this) { - return value; - } - - var Promise = this; - - return new Promise(function(resolve) { - resolve(value); - }); - } - - __exports__.resolve = resolve; - }); -define("promise/utils", - ["exports"], - function(__exports__) { - "use strict"; - function objectOrFunction(x) { - return isFunction(x) || (typeof x === "object" && x !== null); - } - - function isFunction(x) { - return typeof x === "function"; - } - - function isArray(x) { - return Object.prototype.toString.call(x) === "[object Array]"; - } - - // Date.now is not available in browsers < IE9 - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility - var now = Date.now || function() { return new Date().getTime(); }; - - - __exports__.objectOrFunction = objectOrFunction; - __exports__.isFunction = isFunction; - __exports__.isArray = isArray; - __exports__.now = now; - }); -requireModule('promise/polyfill').polyfill(); -}());(function() { - 'use strict'; - - // Sadly, the best way to save binary data in WebSQL/localStorage is serializing - // it to Base64, so this is how we store it to prevent very strange errors with less - // verbose ways of binary <-> string data storage. - var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - - var SERIALIZED_MARKER = '__lfsc__:'; - var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length; - - // OMG the serializations! - var TYPE_ARRAYBUFFER = 'arbf'; - var TYPE_BLOB = 'blob'; - var TYPE_INT8ARRAY = 'si08'; - var TYPE_UINT8ARRAY = 'ui08'; - var TYPE_UINT8CLAMPEDARRAY = 'uic8'; - var TYPE_INT16ARRAY = 'si16'; - var TYPE_INT32ARRAY = 'si32'; - var TYPE_UINT16ARRAY = 'ur16'; - var TYPE_UINT32ARRAY = 'ui32'; - var TYPE_FLOAT32ARRAY = 'fl32'; - var TYPE_FLOAT64ARRAY = 'fl64'; - var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH + - TYPE_ARRAYBUFFER.length; - - // Serialize a value, afterwards executing a callback (which usually - // instructs the `setItem()` callback/promise to be executed). This is how - // we store binary data with localStorage. - function serialize(value, callback) { - var valueString = ''; - if (value) { - valueString = value.toString(); - } - - // Cannot use `value instanceof ArrayBuffer` or such here, as these - // checks fail when running the tests using casper.js... - // - // TODO: See why those tests fail and use a better solution. - if (value && (value.toString() === '[object ArrayBuffer]' || - value.buffer && - value.buffer.toString() === '[object ArrayBuffer]')) { - // Convert binary arrays to a string and prefix the string with - // a special marker. - var buffer; - var marker = SERIALIZED_MARKER; - - if (value instanceof ArrayBuffer) { - buffer = value; - marker += TYPE_ARRAYBUFFER; - } else { - buffer = value.buffer; - - if (valueString === '[object Int8Array]') { - marker += TYPE_INT8ARRAY; - } else if (valueString === '[object Uint8Array]') { - marker += TYPE_UINT8ARRAY; - } else if (valueString === '[object Uint8ClampedArray]') { - marker += TYPE_UINT8CLAMPEDARRAY; - } else if (valueString === '[object Int16Array]') { - marker += TYPE_INT16ARRAY; - } else if (valueString === '[object Uint16Array]') { - marker += TYPE_UINT16ARRAY; - } else if (valueString === '[object Int32Array]') { - marker += TYPE_INT32ARRAY; - } else if (valueString === '[object Uint32Array]') { - marker += TYPE_UINT32ARRAY; - } else if (valueString === '[object Float32Array]') { - marker += TYPE_FLOAT32ARRAY; - } else if (valueString === '[object Float64Array]') { - marker += TYPE_FLOAT64ARRAY; - } else { - callback(new Error('Failed to get type for BinaryArray')); - } - } - - callback(marker + bufferToString(buffer)); - } else if (valueString === '[object Blob]') { - // Conver the blob to a binaryArray and then to a string. - var fileReader = new FileReader(); - - fileReader.onload = function() { - var str = bufferToString(this.result); - - callback(SERIALIZED_MARKER + TYPE_BLOB + str); - }; - - fileReader.readAsArrayBuffer(value); - } else { - try { - callback(JSON.stringify(value)); - } catch (e) { - window.console.error("Couldn't convert value into a JSON " + - 'string: ', value); - - callback(null, e); - } - } - } - - // Deserialize data we've inserted into a value column/field. We place - // special markers into our strings to mark them as encoded; this isn't - // as nice as a meta field, but it's the only sane thing we can do whilst - // keeping localStorage support intact. - // - // Oftentimes this will just deserialize JSON content, but if we have a - // special marker (SERIALIZED_MARKER, defined above), we will extract - // some kind of arraybuffer/binary data/typed array out of the string. - function deserialize(value) { - // If we haven't marked this string as being specially serialized (i.e. - // something other than serialized JSON), we can just return it and be - // done with it. - if (value.substring(0, - SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) { - return JSON.parse(value); - } - - // The following code deals with deserializing some kind of Blob or - // TypedArray. First we separate out the type of data we're dealing - // with from the data itself. - var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH); - var type = value.substring(SERIALIZED_MARKER_LENGTH, - TYPE_SERIALIZED_MARKER_LENGTH); - - var buffer = stringToBuffer(serializedString); - - // Return the right type based on the code/type set during - // serialization. - switch (type) { - case TYPE_ARRAYBUFFER: - return buffer; - case TYPE_BLOB: - return new Blob([buffer]); - case TYPE_INT8ARRAY: - return new Int8Array(buffer); - case TYPE_UINT8ARRAY: - return new Uint8Array(buffer); - case TYPE_UINT8CLAMPEDARRAY: - return new Uint8ClampedArray(buffer); - case TYPE_INT16ARRAY: - return new Int16Array(buffer); - case TYPE_UINT16ARRAY: - return new Uint16Array(buffer); - case TYPE_INT32ARRAY: - return new Int32Array(buffer); - case TYPE_UINT32ARRAY: - return new Uint32Array(buffer); - case TYPE_FLOAT32ARRAY: - return new Float32Array(buffer); - case TYPE_FLOAT64ARRAY: - return new Float64Array(buffer); - default: - throw new Error('Unkown type: ' + type); - } - } - - function stringToBuffer(serializedString) { - // Fill the string into a ArrayBuffer. - var bufferLength = serializedString.length * 0.75; - var len = serializedString.length; - var i; - var p = 0; - var encoded1, encoded2, encoded3, encoded4; - - if (serializedString[serializedString.length - 1] === '=') { - bufferLength--; - if (serializedString[serializedString.length - 2] === '=') { - bufferLength--; - } - } - - var buffer = new ArrayBuffer(bufferLength); - var bytes = new Uint8Array(buffer); - - for (i = 0; i < len; i+=4) { - encoded1 = BASE_CHARS.indexOf(serializedString[i]); - encoded2 = BASE_CHARS.indexOf(serializedString[i+1]); - encoded3 = BASE_CHARS.indexOf(serializedString[i+2]); - encoded4 = BASE_CHARS.indexOf(serializedString[i+3]); - - /*jslint bitwise: true */ - bytes[p++] = (encoded1 << 2) | (encoded2 >> 4); - bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2); - bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63); - } - return buffer; - } - - // Converts a buffer to a string to store, serialized, in the backend - // storage library. - function bufferToString(buffer) { - // base64-arraybuffer - var bytes = new Uint8Array(buffer); - var base64String = ''; - var i; - - for (i = 0; i < bytes.length; i += 3) { - /*jslint bitwise: true */ - base64String += BASE_CHARS[bytes[i] >> 2]; - base64String += BASE_CHARS[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)]; - base64String += BASE_CHARS[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)]; - base64String += BASE_CHARS[bytes[i + 2] & 63]; - } - - if ((bytes.length % 3) === 2) { - base64String = base64String.substring(0, base64String.length - 1) + '='; - } else if (bytes.length % 3 === 1) { - base64String = base64String.substring(0, base64String.length - 2) + '=='; - } - - return base64String; - } - - var localforageSerializer = { - serialize: serialize, - deserialize: deserialize, - stringToBuffer: stringToBuffer, - bufferToString: bufferToString - }; - - if (typeof module !== 'undefined' && module.exports) { - module.exports = localforageSerializer; - } else if (typeof define === 'function' && define.amd) { - define('localforageSerializer', function() { - return localforageSerializer; - }); - } else { - this.localforageSerializer = localforageSerializer; - } -}).call(window); -// Some code originally from async_storage.js in -// [Gaia](https://github.com/mozilla-b2g/gaia). -(function() { - 'use strict'; - - // Originally found in https://github.com/mozilla-b2g/gaia/blob/e8f624e4cc9ea945727278039b3bc9bcb9f8667a/shared/js/async_storage.js - - // Promises! - var Promise = (typeof module !== 'undefined' && module.exports) ? - require('promise') : this.Promise; - - // Initialize IndexedDB; fall back to vendor-prefixed versions if needed. - var indexedDB = indexedDB || this.indexedDB || this.webkitIndexedDB || - this.mozIndexedDB || this.OIndexedDB || - this.msIndexedDB; - - // If IndexedDB isn't available, we get outta here! - if (!indexedDB) { - return; - } - - // Open the IndexedDB 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] = options[i]; - } - } - - return new Promise(function(resolve, reject) { - var openreq = indexedDB.open(dbInfo.name, dbInfo.version); - openreq.onerror = function() { - reject(openreq.error); - }; - openreq.onupgradeneeded = function() { - // First time setup: create an empty object store - openreq.result.createObjectStore(dbInfo.storeName); - }; - openreq.onsuccess = function() { - dbInfo.db = openreq.result; - self._dbInfo = dbInfo; - resolve(); - }; - }); - } - - function getItem(key, callback) { - var self = this; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(key); - } - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly') - .objectStore(dbInfo.storeName); - var req = store.get(key); - - req.onsuccess = function() { - var value = req.result; - if (value === undefined) { - value = null; - } - - resolve(value); - }; - - req.onerror = function() { - reject(req.error); - }; - })["catch"](reject); - }); - - executeDeferedCallback(promise, callback); - return promise; - } - - // Iterate over all items stored in database. - function iterate(iterator, callback) { - var self = this; - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly') - .objectStore(dbInfo.storeName); - - var req = store.openCursor(); - var iterationNumber = 1; - - req.onsuccess = function() { - var cursor = req.result; - - if (cursor) { - var result = iterator(cursor.value, cursor.key, iterationNumber++); - - if (result !== void(0)) { - resolve(result); - } else { - cursor["continue"](); - } - } else { - resolve(); - } - }; - - req.onerror = function() { - reject(req.error); - }; - })["catch"](reject); - }); - - executeDeferedCallback(promise, callback); - - return promise; - } - - function setItem(key, value, callback) { - var self = this; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(key); - } - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite'); - var store = transaction.objectStore(dbInfo.storeName); - - // The reason we don't _save_ null is because IE 10 does - // not support saving the `null` type in IndexedDB. How - // ironic, given the bug below! - // See: https://github.com/mozilla/localForage/issues/161 - if (value === null) { - value = undefined; - } - - var req = store.put(value, key); - transaction.oncomplete = function() { - // Cast to undefined so the value passed to - // callback/promise is the same as what one would get out - // of `getItem()` later. This leads to some weirdness - // (setItem('foo', undefined) will return `null`), but - // it's not my fault localStorage is our baseline and that - // it's weird. - if (value === undefined) { - value = null; - } - - resolve(value); - }; - transaction.onabort = transaction.onerror = function() { - reject(req.error); - }; - })["catch"](reject); - }); - - executeDeferedCallback(promise, callback); - return promise; - } - - function removeItem(key, callback) { - var self = this; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(key); - } - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite'); - var store = transaction.objectStore(dbInfo.storeName); - - // We use a Grunt task to make this safe for IE and some - // versions of Android (including those used by Cordova). - // Normally IE won't like `.delete()` and will insist on - // using `['delete']()`, but we have a build step that - // fixes this for us now. - var req = store["delete"](key); - transaction.oncomplete = function() { - resolve(); - }; - - transaction.onerror = function() { - reject(req.error); - }; - - // The request will be aborted if we've exceeded our storage - // space. In this case, we will reject with a specific - // "QuotaExceededError". - transaction.onabort = function(event) { - var error = event.target.error; - if (error === 'QuotaExceededError') { - reject(error); - } - }; - })["catch"](reject); - }); - - executeDeferedCallback(promise, callback); - return promise; - } - - function clear(callback) { - var self = this; - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite'); - var store = transaction.objectStore(dbInfo.storeName); - var req = store.clear(); - - transaction.oncomplete = function() { - resolve(); - }; - - transaction.onabort = transaction.onerror = function() { - reject(req.error); - }; - })["catch"](reject); - }); - - executeDeferedCallback(promise, callback); - return promise; - } - - function length(callback) { - var self = this; - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly') - .objectStore(dbInfo.storeName); - var req = store.count(); - - req.onsuccess = function() { - resolve(req.result); - }; - - req.onerror = function() { - reject(req.error); - }; - })["catch"](reject); - }); - - executeCallback(promise, callback); - return promise; - } - - function key(n, callback) { - var self = this; - - var promise = new Promise(function(resolve, reject) { - if (n < 0) { - resolve(null); - - return; - } - - self.ready().then(function() { - var dbInfo = self._dbInfo; - var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly') - .objectStore(dbInfo.storeName); - - var advanced = false; - var req = store.openCursor(); - req.onsuccess = function() { - var cursor = req.result; - if (!cursor) { - // this means there weren't enough keys - resolve(null); - - return; - } - - if (n === 0) { - // We have the first key, return it if that's what they - // wanted. - resolve(cursor.key); - } else { - if (!advanced) { - // Otherwise, ask the cursor to skip ahead n - // records. - advanced = true; - cursor.advance(n); - } else { - // When we get here, we've got the nth key. - resolve(cursor.key); - } - } - }; - - req.onerror = function() { - reject(req.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; - var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly') - .objectStore(dbInfo.storeName); - - var req = store.openCursor(); - var keys = []; - - req.onsuccess = function() { - var cursor = req.result; - - if (!cursor) { - resolve(keys); - return; - } - - keys.push(cursor.key); - cursor["continue"](); - }; - - req.onerror = function() { - reject(req.error); - }; - })["catch"](reject); - }); - - executeCallback(promise, callback); - return promise; - } - - function executeCallback(promise, callback) { - if (callback) { - promise.then(function(result) { - callback(null, result); - }, function(error) { - callback(error); - }); - } - } - - function executeDeferedCallback(promise, callback) { - if (callback) { - promise.then(function(result) { - deferCallback(callback, result); - }, function(error) { - callback(error); - }); - } - } - - // Under Chrome the callback is called before the changes (save, clear) - // are actually made. So we use a defer function which wait that the - // call stack to be empty. - // For more info : https://github.com/mozilla/localForage/issues/175 - // Pull request : https://github.com/mozilla/localForage/pull/178 - function deferCallback(callback, result) { - if (callback) { - return setTimeout(function() { - return callback(null, result); - }, 0); - } - } - - var asyncStorage = { - _driver: 'asyncStorage', - _initStorage: _initStorage, - iterate: iterate, - getItem: getItem, - setItem: setItem, - removeItem: removeItem, - clear: clear, - length: length, - key: key, - keys: keys - }; - - if (typeof module !== 'undefined' && module.exports) { - module.exports = asyncStorage; - } else if (typeof define === 'function' && define.amd) { - define('asyncStorage', function() { - return asyncStorage; - }); - } else { - this.asyncStorage = asyncStorage; - } -}).call(window); -// 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). -(function() { - 'use strict'; - - // Promises! - var Promise = (typeof module !== 'undefined' && module.exports) ? - require('promise') : this.Promise; - - var globalObject = this; - var serializer = null; - var localStorage = null; - - // If the app is running inside a Google Chrome packaged webapp, or some - // other context where localStorage isn't available, we don't use - // localStorage. This feature detection is preferred over the old - // `if (window.chrome && window.chrome.runtime)` code. - // See: https://github.com/mozilla/localForage/issues/68 - try { - // If localStorage isn't available, we get outta here! - // This should be inside a try catch - if (!this.localStorage || !('setItem' in this.localStorage)) { - return; - } - // Initialize localStorage and create a variable to use throughout - // the code. - localStorage = this.localStorage; - } catch (e) { - return; - } - - var ModuleType = { - DEFINE: 1, - EXPORT: 2, - WINDOW: 3 - }; - - // Attaching to window (i.e. no module loader) is the assumed, - // simple default. - var moduleType = ModuleType.WINDOW; - - // Find out what kind of module setup we have; if none, we'll just attach - // localForage to the main window. - if (typeof module !== 'undefined' && module.exports) { - moduleType = ModuleType.EXPORT; - } else if (typeof define === 'function' && define.amd) { - moduleType = ModuleType.DEFINE; - } - - // 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 = dbInfo.name + '/'; - - self._dbInfo = dbInfo; - - var serializerPromise = new Promise(function(resolve/*, reject*/) { - // We allow localForage to be declared as a module or as a - // library available without AMD/require.js. - if (moduleType === ModuleType.DEFINE) { - require(['localforageSerializer'], resolve); - } else if (moduleType === ModuleType.EXPORT) { - // Making it browserify friendly - resolve(require('./../utils/serializer')); - } else { - resolve(globalObject.localforageSerializer); - } - }); - - return serializerPromise.then(function(lib) { - serializer = lib; - 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; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(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 = 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 keyPrefix = self._dbInfo.keyPrefix; - var keyPrefixLength = keyPrefix.length; - var length = localStorage.length; - - for (var i = 0; i < length; i++) { - var key = localStorage.key(i); - 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 = serializer.deserialize(value); - } - - value = iterator(value, key.substring(keyPrefixLength), i + 1); - - 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++) { - if (localStorage.key(i).indexOf(dbInfo.keyPrefix) === 0) { - keys.push(localStorage.key(i).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; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(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; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(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) { - serializer.serialize(value, function(value, error) { - if (error) { - reject(error); - } else { - try { - var dbInfo = self._dbInfo; - 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 executeCallback(promise, callback) { - if (callback) { - promise.then(function(result) { - callback(null, result); - }, function(error) { - callback(error); - }); - } - } - - var localStorageWrapper = { - _driver: 'localStorageWrapper', - _initStorage: _initStorage, - // Default API, from Gaia/localStorage. - iterate: iterate, - getItem: getItem, - setItem: setItem, - removeItem: removeItem, - clear: clear, - length: length, - key: key, - keys: keys - }; - - if (moduleType === ModuleType.EXPORT) { - module.exports = localStorageWrapper; - } else if (moduleType === ModuleType.DEFINE) { - define('localStorageWrapper', function() { - return localStorageWrapper; - }); - } else { - this.localStorageWrapper = localStorageWrapper; - } -}).call(window); -/* - * Includes code from: - * - * base64-arraybuffer - * https://github.com/niklasvh/base64-arraybuffer - * - * Copyright (c) 2012 Niklas von Hertzen - * Licensed under the MIT license. - */ -(function() { - 'use strict'; - - // Promises! - var Promise = (typeof module !== 'undefined' && module.exports) ? - require('promise') : this.Promise; - - var globalObject = this; - var serializer = null; - var openDatabase = this.openDatabase; - - // If WebSQL methods aren't available, we can stop now. - if (!openDatabase) { - return; - } - - var ModuleType = { - DEFINE: 1, - EXPORT: 2, - WINDOW: 3 - }; - - // Attaching to window (i.e. no module loader) is the assumed, - // simple default. - var moduleType = ModuleType.WINDOW; - - // Find out what kind of module setup we have; if none, we'll just attach - // localForage to the main window. - if (typeof module !== 'undefined' && module.exports) { - moduleType = ModuleType.EXPORT; - } else if (typeof define === 'function' && define.amd) { - moduleType = ModuleType.DEFINE; - } - - // 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 serializerPromise = new Promise(function(resolve/*, reject*/) { - // We allow localForage to be declared as a module or as a - // library available without AMD/require.js. - if (moduleType === ModuleType.DEFINE) { - require(['localforageSerializer'], resolve); - } else if (moduleType === ModuleType.EXPORT) { - // Making it browserify friendly - resolve(require('./../utils/serializer')); - } else { - resolve(globalObject.localforageSerializer); - } - }); - - 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 self.setDriver(self.LOCALSTORAGE).then(function() { - return self._initStorage(options); -}).then(resolve)["catch"](reject); - } - - // Create our key/value table if it doesn't exist. - dbInfo.db.transaction(function(t) { - t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName + - ' (id INTEGER PRIMARY KEY, key unique, value)', [], - function() { - self._dbInfo = dbInfo; - resolve(); - }, function(t, error) { - reject(error); - }); - }); - }); - - return serializerPromise.then(function(lib) { - serializer = lib; - return dbInfoPromise; - }); - } - - function getItem(key, callback) { - var self = this; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(key); - } - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - dbInfo.db.transaction(function(t) { - t.executeSql('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 = 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) { - t.executeSql('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 = 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) { - var self = this; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(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; - - serializer.serialize(value, function(value, error) { - if (error) { - reject(error); - } else { - var dbInfo = self._dbInfo; - dbInfo.db.transaction(function(t) { - t.executeSql('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. - // - // TODO: Try to re-run the transaction. - reject(sqlError); - } - }); - } - }); - })["catch"](reject); - }); - - executeCallback(promise, callback); - return promise; - } - - function removeItem(key, callback) { - var self = this; - - // Cast the key to a string, as that's all we can set as a key. - if (typeof key !== 'string') { - window.console.warn(key + - ' used as a key, but it is not a string.'); - key = String(key); - } - - var promise = new Promise(function(resolve, reject) { - self.ready().then(function() { - var dbInfo = self._dbInfo; - dbInfo.db.transaction(function(t) { - t.executeSql('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) { - t.executeSql('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. - t.executeSql('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) { - t.executeSql('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) { - t.executeSql('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; - } - - function executeCallback(promise, callback) { - if (callback) { - promise.then(function(result) { - callback(null, result); - }, function(error) { - callback(error); - }); - } - } - - var webSQLStorage = { - _driver: 'webSQLStorage', - _initStorage: _initStorage, - iterate: iterate, - getItem: getItem, - setItem: setItem, - removeItem: removeItem, - clear: clear, - length: length, - key: key, - keys: keys - }; - - if (moduleType === ModuleType.DEFINE) { - define('webSQLStorage', function() { - return webSQLStorage; - }); - } else if (moduleType === ModuleType.EXPORT) { - module.exports = webSQLStorage; - } else { - this.webSQLStorage = webSQLStorage; - } -}).call(window); -(function() { - 'use strict'; - - // Promises! - var Promise = (typeof module !== 'undefined' && module.exports) ? - require('promise') : this.Promise; - - // Custom drivers are stored here when `defineDriver()` is called. - // They are shared across all instances of localForage. - var CustomDrivers = {}; - - var DriverType = { - INDEXEDDB: 'asyncStorage', - LOCALSTORAGE: 'localStorageWrapper', - WEBSQL: 'webSQLStorage' - }; - - var DefaultDriverOrder = [ - DriverType.INDEXEDDB, - DriverType.WEBSQL, - DriverType.LOCALSTORAGE - ]; - - var LibraryMethods = [ - 'clear', - 'getItem', - 'iterate', - 'key', - 'keys', - 'length', - 'removeItem', - 'setItem' - ]; - - var ModuleType = { - DEFINE: 1, - EXPORT: 2, - WINDOW: 3 - }; - - var DefaultConfig = { - description: '', - driver: DefaultDriverOrder.slice(), - name: 'localforage', - // Default DB size is _JUST UNDER_ 5MB, as it's the highest size - // we can use without a prompt. - size: 4980736, - storeName: 'keyvaluepairs', - version: 1.0 - }; - - // Attaching to window (i.e. no module loader) is the assumed, - // simple default. - var moduleType = ModuleType.WINDOW; - - // Find out what kind of module setup we have; if none, we'll just attach - // localForage to the main window. - if (typeof module !== 'undefined' && module.exports) { - moduleType = ModuleType.EXPORT; - } else if (typeof define === 'function' && define.amd) { - moduleType = ModuleType.DEFINE; - } - - // Check to see if IndexedDB is available and if it is the latest - // implementation; it's our preferred backend library. We use "_spec_test" - // as the name of the database because it's not the one we'll operate on, - // but it's useful to make sure its using the right spec. - // See: https://github.com/mozilla/localForage/issues/128 - var driverSupport = (function(self) { - // Initialize IndexedDB; fall back to vendor-prefixed versions - // if needed. - var indexedDB = indexedDB || self.indexedDB || self.webkitIndexedDB || - self.mozIndexedDB || self.OIndexedDB || - self.msIndexedDB; - - var result = {}; - - result[DriverType.WEBSQL] = !!self.openDatabase; - result[DriverType.INDEXEDDB] = !!(function() { - // We mimic PouchDB here; just UA test for Safari (which, as of - // iOS 8/Yosemite, doesn't properly support IndexedDB). - // IndexedDB support is broken and different from Blink's. - // This is faster than the test case (and it's sync), so we just - // do this. *SIGH* - // http://bl.ocks.org/nolanlawson/raw/c83e9039edf2278047e9/ - // - // We test for openDatabase because IE Mobile identifies itself - // as Safari. Oh the lulz... - if (typeof self.openDatabase !== 'undefined' && self.navigator && - self.navigator.userAgent && - /Safari/.test(self.navigator.userAgent) && - !/Chrome/.test(self.navigator.userAgent)) { - return false; - } - try { - return indexedDB && - typeof indexedDB.open === 'function' && - // Some Samsung/HTC Android 4.0-4.3 devices - // have older IndexedDB specs; if this isn't available - // their IndexedDB is too old for us to use. - // (Replaces the onupgradeneeded test.) - typeof self.IDBKeyRange !== 'undefined'; - } catch (e) { - return false; - } - })(); - - result[DriverType.LOCALSTORAGE] = !!(function() { - try { - return (self.localStorage && - ('setItem' in self.localStorage) && - (self.localStorage.setItem)); - } catch (e) { - return false; - } - })(); - - return result; - })(this); - - var isArray = Array.isArray || function(arg) { - return Object.prototype.toString.call(arg) === '[object Array]'; - }; - - function callWhenReady(localForageInstance, libraryMethod) { - localForageInstance[libraryMethod] = function() { - var _args = arguments; - return localForageInstance.ready().then(function() { - return localForageInstance[libraryMethod].apply(localForageInstance, _args); - }); - }; - } - - function extend() { - for (var i = 1; i < arguments.length; i++) { - var arg = arguments[i]; - - if (arg) { - for (var key in arg) { - if (arg.hasOwnProperty(key)) { - if (isArray(arg[key])) { - arguments[0][key] = arg[key].slice(); - } else { - arguments[0][key] = arg[key]; - } - } - } - } - } - - return arguments[0]; - } - - function isLibraryDriver(driverName) { - for (var driver in DriverType) { - if (DriverType.hasOwnProperty(driver) && - DriverType[driver] === driverName) { - return true; - } - } - - return false; - } - - var globalObject = this; - - function LocalForage(options) { - this._config = extend({}, DefaultConfig, options); - this._driverSet = null; - this._ready = false; - this._dbInfo = null; - - // Add a stub for each driver API method that delays the call to the - // corresponding driver method until localForage is ready. These stubs - // will be replaced by the driver methods as soon as the driver is - // loaded, so there is no performance impact. - for (var i = 0; i < LibraryMethods.length; i++) { - callWhenReady(this, LibraryMethods[i]); - } - - this.setDriver(this._config.driver); - } - - LocalForage.prototype.INDEXEDDB = DriverType.INDEXEDDB; - LocalForage.prototype.LOCALSTORAGE = DriverType.LOCALSTORAGE; - LocalForage.prototype.WEBSQL = DriverType.WEBSQL; - - // Set any config values for localForage; can be called anytime before - // the first API call (e.g. `getItem`, `setItem`). - // We loop through options so we don't overwrite existing config - // values. - LocalForage.prototype.config = function(options) { - // If the options argument is an object, we use it to set values. - // Otherwise, we return either a specified config value or all - // config values. - if (typeof(options) === 'object') { - // If localforage is ready and fully initialized, we can't set - // any new configuration values. Instead, we return an error. - if (this._ready) { - return new Error("Can't call config() after localforage " + - 'has been used.'); - } - - for (var i in options) { - if (i === 'storeName') { - options[i] = options[i].replace(/\W/g, '_'); - } - - this._config[i] = options[i]; - } - - // after all config options are set and - // the driver option is used, try setting it - if ('driver' in options && options.driver) { - this.setDriver(this._config.driver); - } - - return true; - } else if (typeof(options) === 'string') { - return this._config[options]; - } else { - return this._config; - } - }; - - // Used to define a custom driver, shared across all instances of - // localForage. - LocalForage.prototype.defineDriver = function(driverObject, callback, - errorCallback) { - var defineDriver = new Promise(function(resolve, reject) { - try { - var driverName = driverObject._driver; - var complianceError = new Error( - 'Custom driver not compliant; see ' + - 'https://mozilla.github.io/localForage/#definedriver' - ); - var namingError = new Error( - 'Custom driver name already in use: ' + driverObject._driver - ); - - // A driver name should be defined and not overlap with the - // library-defined, default drivers. - if (!driverObject._driver) { - reject(complianceError); - return; - } - if (isLibraryDriver(driverObject._driver)) { - reject(namingError); - return; - } - - var customDriverMethods = LibraryMethods.concat('_initStorage'); - for (var i = 0; i < customDriverMethods.length; i++) { - var customDriverMethod = customDriverMethods[i]; - if (!customDriverMethod || - !driverObject[customDriverMethod] || - typeof driverObject[customDriverMethod] !== 'function') { - reject(complianceError); - return; - } - } - - var supportPromise = Promise.resolve(true); - if ('_support' in driverObject) { - if (driverObject._support && typeof driverObject._support === 'function') { - supportPromise = driverObject._support(); - } else { - supportPromise = Promise.resolve(!!driverObject._support); - } - } - - supportPromise.then(function(supportResult) { - driverSupport[driverName] = supportResult; - CustomDrivers[driverName] = driverObject; - resolve(); - }, reject); - } catch (e) { - reject(e); - } - }); - - defineDriver.then(callback, errorCallback); - return defineDriver; - }; - - LocalForage.prototype.driver = function() { - return this._driver || null; - }; - - LocalForage.prototype.ready = function(callback) { - var self = this; - - var ready = new Promise(function(resolve, reject) { - self._driverSet.then(function() { - if (self._ready === null) { - self._ready = self._initStorage(self._config); - } - - self._ready.then(resolve, reject); - })["catch"](reject); - }); - - ready.then(callback, callback); - return ready; - }; - - LocalForage.prototype.setDriver = function(drivers, callback, - errorCallback) { - var self = this; - - if (typeof drivers === 'string') { - drivers = [drivers]; - } - - this._driverSet = new Promise(function(resolve, reject) { - var driverName = self._getFirstSupportedDriver(drivers); - var error = new Error('No available storage method found.'); - - if (!driverName) { - self._driverSet = Promise.reject(error); - reject(error); - return; - } - - self._dbInfo = null; - self._ready = null; - - if (isLibraryDriver(driverName)) { - // We allow localForage to be declared as a module or as a - // library available without AMD/require.js. - if (moduleType === ModuleType.DEFINE) { - require([driverName], function(lib) { - self._extend(lib); - - resolve(); - }); - - return; - } else if (moduleType === ModuleType.EXPORT) { - // Making it browserify friendly - var driver; - switch (driverName) { - case self.INDEXEDDB: - driver = require('./drivers/indexeddb'); - break; - case self.LOCALSTORAGE: - driver = require('./drivers/localstorage'); - break; - case self.WEBSQL: - driver = require('./drivers/websql'); - } - - self._extend(driver); - } else { - self._extend(globalObject[driverName]); - } - } else if (CustomDrivers[driverName]) { - self._extend(CustomDrivers[driverName]); - } else { - self._driverSet = Promise.reject(error); - reject(error); - return; - } - - resolve(); - }); - - function setDriverToConfig() { - self._config.driver = self.driver(); - } - this._driverSet.then(setDriverToConfig, setDriverToConfig); - - this._driverSet.then(callback, errorCallback); - return this._driverSet; - }; - - LocalForage.prototype.supports = function(driverName) { - return !!driverSupport[driverName]; - }; - - LocalForage.prototype._extend = function(libraryMethodsAndProperties) { - extend(this, libraryMethodsAndProperties); - }; - - // Used to determine which driver we should use as the backend for this - // instance of localForage. - LocalForage.prototype._getFirstSupportedDriver = function(drivers) { - if (drivers && isArray(drivers)) { - for (var i = 0; i < drivers.length; i++) { - var driver = drivers[i]; - - if (this.supports(driver)) { - return driver; - } - } - } - - return null; - }; - - LocalForage.prototype.createInstance = function(options) { - return new LocalForage(options); - }; - - // The actual localForage object that we expose as a module or via a - // global. It's extended by pulling in one of our other libraries. - var localForage = new LocalForage(); - - // We allow localForage to be declared as a module or as a library - // available without AMD/require.js. - if (moduleType === ModuleType.DEFINE) { - define('localforage', function() { - return localForage; - }); - } else if (moduleType === ModuleType.EXPORT) { - module.exports = localForage; - } else { - this.localforage = localForage; - } -}).call(window); |