diff options
| author | Pliable Pixels <pliablepixels@gmail.com> | 2017-09-21 12:49:18 -0400 |
|---|---|---|
| committer | Pliable Pixels <pliablepixels@gmail.com> | 2017-09-21 12:49:18 -0400 |
| commit | b28028ac4082842143b0f528d6bc539da6ccb419 (patch) | |
| tree | 1e26ea969a781ed8e323fca4e3c76345113fc694 /www/lib/localforage/src/utils | |
| parent | 676270d21beed31d767a06c89522198c77d5d865 (diff) | |
mega changes, including updates and X
Diffstat (limited to 'www/lib/localforage/src/utils')
| -rw-r--r-- | www/lib/localforage/src/utils/createBlob.js | 29 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/executeCallback.js | 11 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/executeTwoCallbacks.js | 11 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/idb.js | 21 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/isIndexedDBValid.js | 37 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/isLocalStorageValid.js | 11 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/isWebSQLValid.js | 5 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/promise.js | 6 | ||||
| -rw-r--r-- | www/lib/localforage/src/utils/serializer.js | 233 |
9 files changed, 364 insertions, 0 deletions
diff --git a/www/lib/localforage/src/utils/createBlob.js b/www/lib/localforage/src/utils/createBlob.js new file mode 100644 index 00000000..4d698551 --- /dev/null +++ b/www/lib/localforage/src/utils/createBlob.js @@ -0,0 +1,29 @@ +// Abstracts constructing a Blob object, so it also works in older +// browsers that don't support the native Blob constructor. (i.e. +// old QtWebKit versions, at least). +// Abstracts constructing a Blob object, so it also works in older +// browsers that don't support the native Blob constructor. (i.e. +// old QtWebKit versions, at least). +function createBlob(parts, properties) { + /* global BlobBuilder,MSBlobBuilder,MozBlobBuilder,WebKitBlobBuilder */ + parts = parts || []; + properties = properties || {}; + try { + return new Blob(parts, properties); + } catch (e) { + if (e.name !== 'TypeError') { + throw e; + } + var Builder = typeof BlobBuilder !== 'undefined' ? BlobBuilder : + typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder : + typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder : + WebKitBlobBuilder; + var builder = new Builder(); + for (var i = 0; i < parts.length; i += 1) { + builder.append(parts[i]); + } + return builder.getBlob(properties.type); + } +} + +export default createBlob; diff --git a/www/lib/localforage/src/utils/executeCallback.js b/www/lib/localforage/src/utils/executeCallback.js new file mode 100644 index 00000000..c6982d4a --- /dev/null +++ b/www/lib/localforage/src/utils/executeCallback.js @@ -0,0 +1,11 @@ +function executeCallback(promise, callback) { + if (callback) { + promise.then(function(result) { + callback(null, result); + }, function(error) { + callback(error); + }); + } +} + +export default executeCallback; diff --git a/www/lib/localforage/src/utils/executeTwoCallbacks.js b/www/lib/localforage/src/utils/executeTwoCallbacks.js new file mode 100644 index 00000000..f98c7585 --- /dev/null +++ b/www/lib/localforage/src/utils/executeTwoCallbacks.js @@ -0,0 +1,11 @@ +function executeTwoCallbacks(promise, callback, errorCallback) { + if (typeof callback === 'function') { + promise.then(callback); + } + + if (typeof errorCallback === 'function') { + promise.catch(errorCallback); + } +} + +export default executeTwoCallbacks; diff --git a/www/lib/localforage/src/utils/idb.js b/www/lib/localforage/src/utils/idb.js new file mode 100644 index 00000000..47541f6a --- /dev/null +++ b/www/lib/localforage/src/utils/idb.js @@ -0,0 +1,21 @@ +function getIDB() { + /* global indexedDB,webkitIndexedDB,mozIndexedDB,OIndexedDB,msIndexedDB */ + if (typeof indexedDB !== 'undefined') { + return indexedDB; + } + if (typeof webkitIndexedDB !== 'undefined') { + return webkitIndexedDB; + } + if (typeof mozIndexedDB !== 'undefined') { + return mozIndexedDB; + } + if (typeof OIndexedDB !== 'undefined') { + return OIndexedDB; + } + if (typeof msIndexedDB !== 'undefined') { + return msIndexedDB; + } +} + +var idb = getIDB(); +export default idb; diff --git a/www/lib/localforage/src/utils/isIndexedDBValid.js b/www/lib/localforage/src/utils/isIndexedDBValid.js new file mode 100644 index 00000000..aa14b6d8 --- /dev/null +++ b/www/lib/localforage/src/utils/isIndexedDBValid.js @@ -0,0 +1,37 @@ +import idb from './idb'; + +function isIndexedDBValid() { + try { + // Initialize IndexedDB; fall back to vendor-prefixed versions + // if needed. + if (!idb) { + return false; + } + // 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 openDatabase !== 'undefined' && typeof navigator !== 'undefined' && + navigator.userAgent && + /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent)) { + return false; + } + + return idb && + typeof idb.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 IDBKeyRange !== 'undefined'; + } catch (e) { + return false; + } +} + +export default isIndexedDBValid; diff --git a/www/lib/localforage/src/utils/isLocalStorageValid.js b/www/lib/localforage/src/utils/isLocalStorageValid.js new file mode 100644 index 00000000..0c7c1245 --- /dev/null +++ b/www/lib/localforage/src/utils/isLocalStorageValid.js @@ -0,0 +1,11 @@ +function isLocalStorageValid() { + try { + return typeof localStorage !== 'undefined' && + ('setItem' in localStorage) && + localStorage.setItem; + } catch (e) { + return false; + } +} + +export default isLocalStorageValid; diff --git a/www/lib/localforage/src/utils/isWebSQLValid.js b/www/lib/localforage/src/utils/isWebSQLValid.js new file mode 100644 index 00000000..1a4386ac --- /dev/null +++ b/www/lib/localforage/src/utils/isWebSQLValid.js @@ -0,0 +1,5 @@ +function isWebSQLValid() { + return typeof openDatabase === 'function'; +} + +export default isWebSQLValid; diff --git a/www/lib/localforage/src/utils/promise.js b/www/lib/localforage/src/utils/promise.js new file mode 100644 index 00000000..177a10d0 --- /dev/null +++ b/www/lib/localforage/src/utils/promise.js @@ -0,0 +1,6 @@ +// This is CommonJS because lie is an external dependency, so Rollup +// can just ignore it. +if (typeof Promise === 'undefined' && typeof require !== 'undefined') { + require('lie/polyfill'); +} +export default Promise; diff --git a/www/lib/localforage/src/utils/serializer.js b/www/lib/localforage/src/utils/serializer.js new file mode 100644 index 00000000..08e5fc8f --- /dev/null +++ b/www/lib/localforage/src/utils/serializer.js @@ -0,0 +1,233 @@ +import createBlob from './createBlob'; + +// 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 BLOB_TYPE_PREFIX = '~~local_forage_type~'; +var BLOB_TYPE_PREFIX_REGEX = /^~~local_forage_type~([^~]+)~/; + +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; + +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; +} + +// 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() { + // Backwards-compatible prefix for the blob type. + var str = BLOB_TYPE_PREFIX + value.type + '~' + + bufferToString(this.result); + + callback(SERIALIZED_MARKER + TYPE_BLOB + str); + }; + + fileReader.readAsArrayBuffer(value); + } else { + try { + callback(JSON.stringify(value)); + } catch (e) { + 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 blobType; + // Backwards-compatible blob type serialization strategy. + // DBs created with older versions of localForage will simply not have the blob type. + if (type === TYPE_BLOB && BLOB_TYPE_PREFIX_REGEX.test(serializedString)) { + var matcher = serializedString.match(BLOB_TYPE_PREFIX_REGEX); + blobType = matcher[1]; + serializedString = serializedString.substring(matcher[0].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 createBlob([buffer], {type: blobType}); + 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); + } +} + +var localforageSerializer = { + serialize: serialize, + deserialize: deserialize, + stringToBuffer: stringToBuffer, + bufferToString: bufferToString +}; + +export default localforageSerializer; |
