Advertisement
Guest User

Untitled

a guest
Apr 25th, 2017
61
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.82 KB | None | 0 0
  1. 'use strict';
  2. function fakeSymbol(key) {
  3. return key + '_Symbol'
  4. }
  5. const __ls = fakeSymbol('localStorage');
  6. const __store = fakeSymbol('store');
  7. const __window = fakeSymbol('window');
  8. const __name = fakeSymbol('name');
  9. const __isWriting = fakeSymbol('isWriting');
  10. const __error = fakeSymbol('error');
  11. function isWindowAndHasLS(window) {
  12. return window && window.localStorage;
  13. }
  14. function isValidObject(object) {
  15. return object && typeof object === "object" && !Array.isArray(object) && !(object instanceof Error);
  16. }
  17. function logError(error) {
  18. console.error(error);
  19. }
  20. function error(message) {
  21. return new Error(message);
  22. }
  23. function keyIsNotAString() {
  24. return error("key should be a string");
  25. }
  26. function isKeyAString(key) {
  27. return typeof key === "string";
  28. }
  29. class Store {
  30. /*
  31. * from object to string
  32. * @param {object}
  33. */
  34. static serialize(data) {
  35. return JSON.stringify(data);
  36. }
  37. /*
  38. * from string to object
  39. * @param {string}
  40. */
  41. static deserialize(string) {
  42. return JSON.parse(string);
  43. }
  44. /*
  45. * cone object
  46. * @param {obj}
  47. */
  48. static clone(obj) {
  49. return JSON.parse(JSON.stringify(obj));
  50. }
  51. /*
  52. * @param {string} name of local storage item
  53. */
  54. constructor(name) {
  55. if (!isWindowAndHasLS(window)) {
  56. return logError(error("window or localStorage is not defined!"));
  57. }
  58. this[__window] = window;
  59. this[__name] = name;
  60. this[__isWriting] = false;
  61. this[__error] = null;
  62. this[__ls] = this[__window].localStorage;
  63. this[__store] = this.__getAndDeserialize();
  64. if (!isValidObject(this[__store])) {
  65. this[__store] = {};
  66. this.__serializeAndSet();
  67. if (this[__error]) {
  68. this.destructor(true);
  69. return this[__error];
  70. }
  71. }
  72. this.__changeStorageHandler = this.__changeStorageHandler.bind(this);
  73. this[__window].addEventListener("storage", this.__changeStorageHandler);
  74. }
  75. /*
  76. * Remove event listener
  77. * @param {boolean} if true, local storage item will be removed
  78. */
  79. destructor(removeStorage) {
  80. this[__window].removeEventListener("storage", this.__changeStorageHandler);
  81. if (removeStorage) {
  82. this[__ls].removeItem(this[__name]);
  83. }
  84. delete this[__window];
  85. delete this[__name];
  86. delete this[__ls];
  87. delete this[__store];
  88. delete this[__isWriting];
  89. }
  90. /*
  91. * you can use multikey: set('boo.bar.baz', 10)
  92. * @param {string} value of key which you want set
  93. * @param {object|number|string|boolean} val which you want set
  94. */
  95. set(key, val) {
  96. if (!isKeyAString(key)) {
  97. return keyIsNotAString();
  98. }
  99. let store = this[__store];
  100. let parts = key.split('.');
  101. let lastKey = parts.pop();
  102. let _val = typeof val === "object" ? Store.clone(val) : val;
  103. if (typeof val === "function") {
  104. _val = val();
  105. }
  106. if (_val === undefined) {
  107. return this.remove(key);
  108. }
  109. parts.forEach(_key => {
  110. if (!isValidObject(store[_key])) {
  111. store[_key] = {};
  112. }
  113. store = store[_key];
  114. });
  115. store[lastKey] = _val;
  116. this[__isWriting] = true;
  117. this.__serializeAndSet();
  118. if (this[__error]) {
  119. return this[__error];
  120. }
  121. return _val;
  122. }
  123. /*
  124. * you can use multikey: get('boo.bar.baz', 10)
  125. * @param {string} value of key which you want get
  126. * @param {object|number|string|boolean} defaultValue if key is undefined
  127. */
  128. get(key, defaultValue) {
  129. if (!arguments.length) {
  130. return this.getAll();
  131. }
  132. if (!isKeyAString(key)) {
  133. return keyIsNotAString();
  134. }
  135. let store = this[__store];
  136. let parts = key.split(".");
  137. let lastKey = parts.pop();
  138. for (let i = 0; i < parts.length; i++) {
  139. let _key = parts[i];
  140. if (store.hasOwnProperty(_key) && isValidObject(store[_key])) {
  141. store = store[_key];
  142. } else {
  143. return defaultValue;
  144. }
  145. }
  146. store = store[lastKey];
  147. if (store === undefined) {
  148. return defaultValue;
  149. }
  150. return typeof store === "object" ? Store.clone(store) : store;
  151. }
  152. /*
  153. * return all local storage data
  154. */
  155. getAll() {
  156. return Store.clone(this[__store]);
  157. }
  158. /*
  159. * you can use multikey: remove('boo.bar.baz')
  160. * @param {string} value of key which you want remove
  161. */
  162. remove(key) {
  163. if (!arguments.length) {
  164. return this.clear();
  165. }
  166. if (!isKeyAString(key)) {
  167. return keyIsNotAString();
  168. }
  169. let store = this[__store];
  170. let parts = key.split('.');
  171. let lastKey = parts.pop();
  172. let val;
  173. for (let i = 0; i < parts.length; i++) {
  174. let _key = parts[i];
  175. if (store.hasOwnProperty(_key) && isValidObject(store[_key])) {
  176. store = store[_key];
  177. } else {
  178. return;
  179. }
  180. }
  181. val = store[lastKey];
  182. delete store[lastKey];
  183. this.__serializeAndSet();
  184. if (this[__error]) {
  185. return this[__error];
  186. }
  187. return val;
  188. }
  189. /*
  190. * Clears local storage.
  191. */
  192. clear() {
  193. let store = this[__store];
  194. this[__store] = {};
  195. this.__serializeAndSet();
  196. return store;
  197. }
  198. __getAndDeserialize() {
  199. try {
  200. return Store.deserialize(this[__ls].getItem(this[__name]));
  201. } catch (e) {
  202. this[__error] = error("Error when trying to get data from localStorage!");
  203. logError(this[__error]);
  204. return this[__error];
  205. }
  206. }
  207. __serializeAndSet() {
  208. try {
  209. this[__ls].setItem(this[__name], Store.serialize(this[__store]));
  210. this[__error] = null;
  211. } catch (e) {
  212. this[__error] = error("Error when trying to set data to localStorage!");
  213. logError(this[__error]);
  214. }
  215. }
  216. __changeStorageHandler(event) {
  217. if (event.key !== this[__name] || this[__isWriting]) {
  218. this[__isWriting] = false;
  219. return;
  220. }
  221. let store = this.__getAndDeserialize();
  222. if (!isValidObject(store)) {
  223. return;
  224. }
  225. this[__store] = store;
  226. }
  227. }
  228. const mockStore = {
  229. get(){},
  230. set(){}
  231. }
  232. export default process.env.BROWSER ? new Store('watchanime') : mockStore;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement