Front end of the Slack clone application.

dummyStorageDriver.js 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. (function() {
  2. 'use strict';
  3. var dummyStorage = {};
  4. // Config the localStorage backend, using options set in the config.
  5. function _initStorage(options) {
  6. var self = this;
  7. var dbInfo = {};
  8. if (options) {
  9. for (var i in options) {
  10. dbInfo[i] = options[i];
  11. }
  12. }
  13. dummyStorage[dbInfo.name] = dbInfo.db = {};
  14. self._dbInfo = dbInfo;
  15. return Promise.resolve();
  16. }
  17. var SERIALIZED_MARKER = '__lfsc__:';
  18. var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
  19. // OMG the serializations!
  20. var TYPE_ARRAYBUFFER = 'arbf';
  21. var TYPE_BLOB = 'blob';
  22. var TYPE_INT8ARRAY = 'si08';
  23. var TYPE_UINT8ARRAY = 'ui08';
  24. var TYPE_UINT8CLAMPEDARRAY = 'uic8';
  25. var TYPE_INT16ARRAY = 'si16';
  26. var TYPE_INT32ARRAY = 'si32';
  27. var TYPE_UINT16ARRAY = 'ur16';
  28. var TYPE_UINT32ARRAY = 'ui32';
  29. var TYPE_FLOAT32ARRAY = 'fl32';
  30. var TYPE_FLOAT64ARRAY = 'fl64';
  31. var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH +
  32. TYPE_ARRAYBUFFER.length;
  33. function clear(callback) {
  34. var self = this;
  35. var promise = new Promise(function(resolve, reject) {
  36. self.ready().then(function() {
  37. var db = self._dbInfo.db;
  38. for (var key in db) {
  39. if (db.hasOwnProperty(key)) {
  40. delete db[key];
  41. // db[key] = undefined;
  42. }
  43. }
  44. resolve();
  45. }).catch(reject);
  46. });
  47. executeCallback(promise, callback);
  48. return promise;
  49. }
  50. function getItem(key, callback) {
  51. var self = this;
  52. // Cast the key to a string, as that's all we can set as a key.
  53. if (typeof key !== 'string') {
  54. window.console.warn(key +
  55. ' used as a key, but it is not a string.');
  56. key = String(key);
  57. }
  58. var promise = new Promise(function(resolve, reject) {
  59. self.ready().then(function() {
  60. try {
  61. var db = self._dbInfo.db;
  62. var result = db[key];
  63. if (result) {
  64. result = _deserialize(result);
  65. }
  66. resolve(result);
  67. } catch (e) {
  68. reject(e);
  69. }
  70. }).catch(reject);
  71. });
  72. executeCallback(promise, callback);
  73. return promise;
  74. }
  75. function iterate(callback) {
  76. var self = this;
  77. var promise = new Promise(function(resolve, reject) {
  78. self.ready().then(function() {
  79. try {
  80. var db = self._dbInfo.db;
  81. for (var key in db) {
  82. var result = db[key];
  83. if (result) {
  84. result = _deserialize(result);
  85. }
  86. callback(result, key);
  87. }
  88. resolve();
  89. } catch (e) {
  90. reject(e);
  91. }
  92. }).catch(reject);
  93. });
  94. executeCallback(promise, callback);
  95. return promise;
  96. }
  97. function key(n, callback) {
  98. var self = this;
  99. var promise = new Promise(function(resolve, reject) {
  100. self.ready().then(function() {
  101. var db = self._dbInfo.db;
  102. var result = null;
  103. var index = 0;
  104. for (var key in db) {
  105. if (db.hasOwnProperty(key) && db[key] !== undefined) {
  106. if (n === index) {
  107. result = key;
  108. break;
  109. }
  110. index++;
  111. }
  112. }
  113. resolve(result);
  114. }).catch(reject);
  115. });
  116. executeCallback(promise, callback);
  117. return promise;
  118. }
  119. function keys(callback) {
  120. var self = this;
  121. var promise = new Promise(function(resolve, reject) {
  122. self.ready().then(function() {
  123. var db = self._dbInfo.db;
  124. var keys = [];
  125. for (var key in db) {
  126. if (db.hasOwnProperty(key)) {
  127. keys.push(key);
  128. }
  129. }
  130. resolve(keys);
  131. }).catch(reject);
  132. });
  133. executeCallback(promise, callback);
  134. return promise;
  135. }
  136. function length(callback) {
  137. var self = this;
  138. var promise = new Promise(function(resolve, reject) {
  139. self.keys().then(function(keys) {
  140. resolve(keys.length);
  141. }).catch(reject);
  142. });
  143. executeCallback(promise, callback);
  144. return promise;
  145. }
  146. function removeItem(key, callback) {
  147. var self = this;
  148. // Cast the key to a string, as that's all we can set as a key.
  149. if (typeof key !== 'string') {
  150. window.console.warn(key +
  151. ' used as a key, but it is not a string.');
  152. key = String(key);
  153. }
  154. var promise = new Promise(function(resolve, reject) {
  155. self.ready().then(function() {
  156. var db = self._dbInfo.db;
  157. if (db.hasOwnProperty(key)) {
  158. delete db[key];
  159. // db[key] = undefined;
  160. }
  161. resolve();
  162. }).catch(reject);
  163. });
  164. executeCallback(promise, callback);
  165. return promise;
  166. }
  167. function setItem(key, value, callback) {
  168. var self = this;
  169. // Cast the key to a string, as that's all we can set as a key.
  170. if (typeof key !== 'string') {
  171. window.console.warn(key +
  172. ' used as a key, but it is not a string.');
  173. key = String(key);
  174. }
  175. var promise = new Promise(function(resolve, reject) {
  176. self.ready().then(function() {
  177. // Convert undefined values to null.
  178. // https://github.com/mozilla/localForage/pull/42
  179. if (value === undefined) {
  180. value = null;
  181. }
  182. // Save the original value to pass to the callback.
  183. var originalValue = value;
  184. _serialize(value, function(value, error) {
  185. if (error) {
  186. reject(error);
  187. } else {
  188. try {
  189. var db = self._dbInfo.db;
  190. db[key] = value;
  191. resolve(originalValue);
  192. } catch (e) {
  193. reject(e);
  194. }
  195. }
  196. });
  197. }).catch(reject);
  198. });
  199. executeCallback(promise, callback);
  200. return promise;
  201. }
  202. // _serialize just like in LocalStorage
  203. function _serialize(value, callback) {
  204. var valueString = '';
  205. if (value) {
  206. valueString = value.toString();
  207. }
  208. // Cannot use `value instanceof ArrayBuffer` or such here, as these
  209. // checks fail when running the tests using casper.js...
  210. //
  211. // TODO: See why those tests fail and use a better solution.
  212. if (value && (value.toString() === '[object ArrayBuffer]' ||
  213. value.buffer &&
  214. value.buffer.toString() === '[object ArrayBuffer]')) {
  215. // Convert binary arrays to a string and prefix the string with
  216. // a special marker.
  217. var buffer;
  218. var marker = SERIALIZED_MARKER;
  219. if (value instanceof ArrayBuffer) {
  220. buffer = value;
  221. marker += TYPE_ARRAYBUFFER;
  222. } else {
  223. buffer = value.buffer;
  224. if (valueString === '[object Int8Array]') {
  225. marker += TYPE_INT8ARRAY;
  226. } else if (valueString === '[object Uint8Array]') {
  227. marker += TYPE_UINT8ARRAY;
  228. } else if (valueString === '[object Uint8ClampedArray]') {
  229. marker += TYPE_UINT8CLAMPEDARRAY;
  230. } else if (valueString === '[object Int16Array]') {
  231. marker += TYPE_INT16ARRAY;
  232. } else if (valueString === '[object Uint16Array]') {
  233. marker += TYPE_UINT16ARRAY;
  234. } else if (valueString === '[object Int32Array]') {
  235. marker += TYPE_INT32ARRAY;
  236. } else if (valueString === '[object Uint32Array]') {
  237. marker += TYPE_UINT32ARRAY;
  238. } else if (valueString === '[object Float32Array]') {
  239. marker += TYPE_FLOAT32ARRAY;
  240. } else if (valueString === '[object Float64Array]') {
  241. marker += TYPE_FLOAT64ARRAY;
  242. } else {
  243. callback(new Error('Failed to get type for BinaryArray'));
  244. }
  245. }
  246. callback(marker + _bufferToString(buffer));
  247. } else if (valueString === '[object Blob]') {
  248. // Conver the blob to a binaryArray and then to a string.
  249. var fileReader = new FileReader();
  250. fileReader.onload = function() {
  251. var str = _bufferToString(this.result);
  252. callback(SERIALIZED_MARKER + TYPE_BLOB + str);
  253. };
  254. fileReader.readAsArrayBuffer(value);
  255. } else {
  256. try {
  257. callback(JSON.stringify(value));
  258. } catch (e) {
  259. window.console.error("Couldn't convert value into a JSON " +
  260. 'string: ', value);
  261. callback(e);
  262. }
  263. }
  264. }
  265. // _deserialize just like in LocalStorage
  266. function _deserialize(value) {
  267. // If we haven't marked this string as being specially serialized (i.e.
  268. // something other than serialized JSON), we can just return it and be
  269. // done with it.
  270. if (value.substring(0,
  271. SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
  272. return JSON.parse(value);
  273. }
  274. // The following code deals with deserializing some kind of Blob or
  275. // TypedArray. First we separate out the type of data we're dealing
  276. // with from the data itself.
  277. var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
  278. var type = value.substring(SERIALIZED_MARKER_LENGTH,
  279. TYPE_SERIALIZED_MARKER_LENGTH);
  280. // Fill the string into a ArrayBuffer.
  281. // 2 bytes for each char.
  282. var buffer = new ArrayBuffer(serializedString.length * 2);
  283. var bufferView = new Uint16Array(buffer);
  284. for (var i = serializedString.length - 1; i >= 0; i--) {
  285. bufferView[i] = serializedString.charCodeAt(i);
  286. }
  287. // Return the right type based on the code/type set during
  288. // serialization.
  289. switch (type) {
  290. case TYPE_ARRAYBUFFER:
  291. return buffer;
  292. case TYPE_BLOB:
  293. return new Blob([buffer]);
  294. case TYPE_INT8ARRAY:
  295. return new Int8Array(buffer);
  296. case TYPE_UINT8ARRAY:
  297. return new Uint8Array(buffer);
  298. case TYPE_UINT8CLAMPEDARRAY:
  299. return new Uint8ClampedArray(buffer);
  300. case TYPE_INT16ARRAY:
  301. return new Int16Array(buffer);
  302. case TYPE_UINT16ARRAY:
  303. return new Uint16Array(buffer);
  304. case TYPE_INT32ARRAY:
  305. return new Int32Array(buffer);
  306. case TYPE_UINT32ARRAY:
  307. return new Uint32Array(buffer);
  308. case TYPE_FLOAT32ARRAY:
  309. return new Float32Array(buffer);
  310. case TYPE_FLOAT64ARRAY:
  311. return new Float64Array(buffer);
  312. default:
  313. throw new Error('Unkown type: ' + type);
  314. }
  315. }
  316. // _bufferToString just like in LocalStorage
  317. function _bufferToString(buffer) {
  318. var str = '';
  319. var uint16Array = new Uint16Array(buffer);
  320. try {
  321. str = String.fromCharCode.apply(null, uint16Array);
  322. } catch (e) {
  323. // This is a fallback implementation in case the first one does
  324. // not work. This is required to get the phantomjs passing...
  325. for (var i = 0; i < uint16Array.length; i++) {
  326. str += String.fromCharCode(uint16Array[i]);
  327. }
  328. }
  329. return str;
  330. }
  331. function executeCallback(promise, callback) {
  332. if (callback) {
  333. promise.then(function(result) {
  334. callback(null, result);
  335. }, function(error) {
  336. callback(error);
  337. });
  338. }
  339. }
  340. var dummyStorageDriver = {
  341. _driver: 'dummyStorageDriver',
  342. _initStorage: _initStorage,
  343. // _supports: function() { return true; }
  344. iterate: iterate,
  345. getItem: getItem,
  346. setItem: setItem,
  347. removeItem: removeItem,
  348. clear: clear,
  349. length: length,
  350. key: key,
  351. keys: keys
  352. };
  353. if (typeof define === 'function' && define.amd) {
  354. define('dummyStorageDriver', function() {
  355. return dummyStorageDriver;
  356. });
  357. } else if (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined') {
  358. module.exports = dummyStorageDriver;
  359. } else {
  360. this.dummyStorageDriver = dummyStorageDriver;
  361. }
  362. }).call(window);